Implement dynamic types, and application context provider support
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 13 Jan 2016 21:52:26 +0000 (16:52 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 5 Feb 2016 23:13:12 +0000 (18:13 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
38 files changed:
configure.ac
include/Makefile.am
include/lttng/ringbuffer-config.h
include/lttng/ust-context-provider.h [new file with mode: 0644]
include/lttng/ust-ctl.h
include/lttng/ust-dynamic-type.h [new file with mode: 0644]
include/lttng/ust-events.h
include/lttng/ust-tracepoint-event.h
include/ust-comm.h
liblttng-ust-comm/lttng-ust-comm.c
liblttng-ust-ctl/ustctl.c
liblttng-ust/Makefile.am
liblttng-ust/lttng-context-cpu-id.c
liblttng-ust/lttng-context-ip.c
liblttng-ust/lttng-context-perf-counters.c
liblttng-ust/lttng-context-procname.c
liblttng-ust/lttng-context-provider.c [new file with mode: 0644]
liblttng-ust/lttng-context-pthread-id.c
liblttng-ust/lttng-context-vpid.c
liblttng-ust/lttng-context-vtid.c
liblttng-ust/lttng-context.c
liblttng-ust/lttng-events.c
liblttng-ust/lttng-filter-interpreter.c
liblttng-ust/lttng-filter-specialize.c
liblttng-ust/lttng-filter-validator.c
liblttng-ust/lttng-filter.c
liblttng-ust/lttng-filter.h
liblttng-ust/lttng-ring-buffer-client.h
liblttng-ust/lttng-ust-comm.c
liblttng-ust/lttng-ust-dynamic-type.c [new file with mode: 0644]
tests/Makefile.am
tests/hello/hello.c
tests/test-app-ctx/Makefile.am [new file with mode: 0644]
tests/test-app-ctx/hello.c [new file with mode: 0644]
tests/test-app-ctx/tp.c [new file with mode: 0644]
tests/test-app-ctx/ust_tests_hello.h [new file with mode: 0644]
tests/ust-variant/Makefile.am [new file with mode: 0644]
tests/ust-variant/ust-variant.c [new file with mode: 0644]

index c92840bcf73785108e799e42abd081c5d0aca8d6..9d972ccf2680c273f1fc6f1844c0b0a7372f1675 100644 (file)
@@ -407,6 +407,7 @@ AC_CONFIG_FILES([
        tests/ust-elf/Makefile
        tests/benchmark/Makefile
        tests/utils/Makefile
+       tests/test-app-ctx/Makefile
        lttng-ust.pc
 ])
 
index 3c9cf24853c45d5e1f85de825be650e589c9e0f2..47c715b191d4387156325346c5630ad872374587 100644 (file)
@@ -36,6 +36,8 @@ noinst_HEADERS = \
        lttng/ust-tid.h \
        lttng/bitfield.h \
        lttng/ust-dlfcn.h \
+       lttng/ust-dynamic-type.h \
+       lttng/ust-context-provider.h \
        helper.h \
        share.h
 
index 87344c94c8285f94b296f318ae58880dedcc7a39..5ae0d8a6a4985500e168ab0e529b8642f0cba554 100644 (file)
@@ -228,7 +228,7 @@ struct lttng_ust_lib_ring_buffer_config {
  * removed.
  */
 #define LTTNG_UST_RING_BUFFER_CTX_PADDING      \
-               (24 - sizeof(int) - sizeof(void *))
+               (24 - sizeof(int) - sizeof(void *) - sizeof(void *))
 struct lttng_ust_lib_ring_buffer_ctx {
        /* input received by lib_ring_buffer_reserve(), saved here. */
        struct channel *chan;           /* channel */
@@ -258,6 +258,7 @@ struct lttng_ust_lib_ring_buffer_ctx {
        unsigned int rflags;            /* reservation flags */
        unsigned int padding1;          /* padding to realign on pointer */
        void *ip;                       /* caller ip address */
+       void *priv2;                    /* 2nd priv data */
        char padding2[LTTNG_UST_RING_BUFFER_CTX_PADDING];
 };
 
@@ -274,12 +275,14 @@ static inline lttng_ust_notrace
 void lib_ring_buffer_ctx_init(struct lttng_ust_lib_ring_buffer_ctx *ctx,
                              struct channel *chan, void *priv,
                              size_t data_size, int largest_align,
-                             int cpu, struct lttng_ust_shm_handle *handle);
+                             int cpu, struct lttng_ust_shm_handle *handle,
+                             void *priv2);
 static inline
 void lib_ring_buffer_ctx_init(struct lttng_ust_lib_ring_buffer_ctx *ctx,
                              struct channel *chan, void *priv,
                              size_t data_size, int largest_align,
-                             int cpu, struct lttng_ust_shm_handle *handle)
+                             int cpu, struct lttng_ust_shm_handle *handle,
+                             void *priv2)
 {
        ctx->chan = chan;
        ctx->priv = priv;
@@ -290,6 +293,7 @@ void lib_ring_buffer_ctx_init(struct lttng_ust_lib_ring_buffer_ctx *ctx,
        ctx->handle = handle;
        ctx->padding1 = 0;
        ctx->ip = 0;
+       ctx->priv2 = priv2;
        memset(ctx->padding2, 0, LTTNG_UST_RING_BUFFER_CTX_PADDING);
 }
 
diff --git a/include/lttng/ust-context-provider.h b/include/lttng/ust-context-provider.h
new file mode 100644 (file)
index 0000000..5b266fa
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef _LTTNG_UST_CONTEXT_PROVIDER_H
+#define _LTTNG_UST_CONTEXT_PROVIDER_H
+
+/*
+ * Copyright 2016 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <lttng/ust-events.h>
+#include <urcu/hlist.h>
+
+struct lttng_ust_context_provider {
+       char *name;
+       size_t (*get_size)(struct lttng_ctx_field *field, size_t offset);
+       void (*record)(struct lttng_ctx_field *field,
+                      struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                      struct lttng_channel *chan);
+       void (*get_value)(struct lttng_ctx_field *field,
+                        struct lttng_ctx_value *value);
+       struct cds_hlist_node node;
+};
+
+int lttng_ust_context_provider_register(struct lttng_ust_context_provider *provider);
+void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider *provider);
+
+int lttng_context_is_app(const char *name);
+
+void lttng_ust_context_set_session_provider(const char *name,
+               size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+               void (*record)(struct lttng_ctx_field *field,
+                       struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                       struct lttng_channel *chan),
+               void (*get_value)(struct lttng_ctx_field *field,
+                       struct lttng_ctx_value *value));
+
+int lttng_ust_add_app_context_to_ctx_rcu(const char *name, struct lttng_ctx **ctx);
+int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
+               const char *name,
+               size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+               void (*record)(struct lttng_ctx_field *field,
+                       struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                       struct lttng_channel *chan),
+               void (*get_value)(struct lttng_ctx_field *field,
+                       struct lttng_ctx_value *value));
+int lttng_context_add_rcu(struct lttng_ctx **ctx_p,
+               const struct lttng_ctx_field *f);
+
+#endif /* _LTTNG_UST_CONTEXT_PROVIDER_H */
index 7a5f969eecd4ebd0fe50a0715e5d5e273dbbcbaf..916eb28049fd35df0e49ad045d5a2b5bfd00cd7f 100644 (file)
@@ -273,6 +273,8 @@ enum ustctl_abstract_types {
        ustctl_atype_sequence,
        ustctl_atype_string,
        ustctl_atype_float,
+       ustctl_atype_variant,
+       ustctl_atype_struct,
        NR_USTCTL_ABSTRACT_TYPES,
 };
 
@@ -345,6 +347,15 @@ struct ustctl_type {
                        struct ustctl_basic_type length_type;
                        struct ustctl_basic_type elem_type;
                } sequence;
+               struct {
+                       uint32_t nr_choices;
+                       char tag_name[LTTNG_UST_SYM_NAME_LEN];
+                       /* Followed by nr_choices struct ustctl_field. */
+               } variant;
+               struct {
+                       uint32_t nr_fields;
+                       /* Followed by nr_fields struct ustctl_field. */
+               } _struct;
                char padding[USTCTL_UST_TYPE_PADDING];
        } u;
 } LTTNG_PACKED;
diff --git a/include/lttng/ust-dynamic-type.h b/include/lttng/ust-dynamic-type.h
new file mode 100644 (file)
index 0000000..d87dc25
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _LTTNG_UST_DYNAMIC_TYPE_H
+#define _LTTNG_UST_DYNAMIC_TYPE_H
+
+/*
+ * Copyright 2016 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <lttng/ust-events.h>
+
+int lttng_ust_dynamic_type_choices(size_t *nr_choices,
+               const struct lttng_event_field **choices);
+const struct lttng_event_field *lttng_ust_dynamic_type_field(int64_t value);
+const struct lttng_event_field *lttng_ust_dynamic_type_tag_field(void);
+
+#endif /* _LTTNG_UST_DYNAMIC_TYPE_H */
index f7cbc1a6dd27c972f6ec195442c7c0bd8913de08..f3ade45c43558acddedefc5baf33d0a59798bef3 100644 (file)
@@ -57,6 +57,8 @@ extern "C" {
 struct lttng_channel;
 struct lttng_session;
 struct lttng_ust_lib_ring_buffer_ctx;
+struct lttng_ust_context_app;
+struct lttng_event_field;
 
 /*
  * Data structures used by tracepoint event declarations, and by the
@@ -86,6 +88,8 @@ enum lttng_abstract_types {
        atype_sequence,
        atype_string,
        atype_float,
+       atype_dynamic,
+       atype_struct,
        NR_ABSTRACT_TYPES,
 };
 
@@ -206,6 +210,10 @@ struct lttng_type {
                        struct lttng_basic_type length_type;
                        struct lttng_basic_type elem_type;
                } sequence;
+               struct {
+                       uint32_t nr_fields;
+                       struct lttng_event_field *fields;       /* Array of fields. */
+               } _struct;
                char padding[LTTNG_UST_TYPE_PADDING];
        } u;
 };
@@ -234,10 +242,29 @@ struct lttng_event_field {
        char padding[LTTNG_UST_EVENT_FIELD_PADDING];
 };
 
-union lttng_ctx_value {
-       int64_t s64;
-       const char *str;
-       double d;
+enum lttng_ust_dynamic_type {
+       LTTNG_UST_DYNAMIC_TYPE_NONE,
+       LTTNG_UST_DYNAMIC_TYPE_S8,
+       LTTNG_UST_DYNAMIC_TYPE_S16,
+       LTTNG_UST_DYNAMIC_TYPE_S32,
+       LTTNG_UST_DYNAMIC_TYPE_S64,
+       LTTNG_UST_DYNAMIC_TYPE_U8,
+       LTTNG_UST_DYNAMIC_TYPE_U16,
+       LTTNG_UST_DYNAMIC_TYPE_U32,
+       LTTNG_UST_DYNAMIC_TYPE_U64,
+       LTTNG_UST_DYNAMIC_TYPE_FLOAT,
+       LTTNG_UST_DYNAMIC_TYPE_DOUBLE,
+       LTTNG_UST_DYNAMIC_TYPE_STRING,
+       _NR_LTTNG_UST_DYNAMIC_TYPES,
+};
+
+struct lttng_ctx_value {
+       enum lttng_ust_dynamic_type sel;
+       union {
+               int64_t s64;
+               const char *str;
+               double d;
+       } u;
 };
 
 struct lttng_perf_counter_field;
@@ -245,17 +272,18 @@ struct lttng_perf_counter_field;
 #define LTTNG_UST_CTX_FIELD_PADDING    40
 struct lttng_ctx_field {
        struct lttng_event_field event_field;
-       size_t (*get_size)(size_t offset);
+       size_t (*get_size)(struct lttng_ctx_field *field, size_t offset);
        void (*record)(struct lttng_ctx_field *field,
                       struct lttng_ust_lib_ring_buffer_ctx *ctx,
                       struct lttng_channel *chan);
        void (*get_value)(struct lttng_ctx_field *field,
-                        union lttng_ctx_value *value);
+                        struct lttng_ctx_value *value);
        union {
                struct lttng_perf_counter_field *perf_counter;
                char padding[LTTNG_UST_CTX_FIELD_PADDING];
        } u;
        void (*destroy)(struct lttng_ctx_field *field);
+       char *field_name;       /* Has ownership, dynamically allocated. */
 };
 
 #define LTTNG_UST_CTX_PADDING  20
@@ -380,6 +408,7 @@ struct lttng_bytecode_runtime {
        uint64_t (*filter)(void *filter_data, const char *filter_stack_data);
        int link_failed;
        struct cds_list_head node;      /* list of bytecode runtime in event */
+       struct lttng_session *session;
 };
 
 /*
@@ -507,6 +536,14 @@ struct lttng_channel {
        int tstate:1;                   /* Transient enable state */
 };
 
+#define LTTNG_UST_STACK_CTX_PADDING    32
+struct lttng_stack_ctx {
+       struct lttng_event *event;
+       struct lttng_ctx *chan_ctx;     /* RCU dereferenced. */
+       struct lttng_ctx *event_ctx;    /* RCU dereferenced. */
+       char padding[LTTNG_UST_STACK_CTX_PADDING];
+};
+
 #define LTTNG_UST_EVENT_HT_BITS                12
 #define LTTNG_UST_EVENT_HT_SIZE                (1U << LTTNG_UST_EVENT_HT_BITS)
 
@@ -551,6 +588,7 @@ struct lttng_session {
        /* New UST 2.8 */
        struct lttng_ust_enum_ht enums_ht;      /* ht of enumerations */
        struct cds_list_head enums_head;
+       struct lttng_ctx *ctx;                  /* contexts for filters. */
 };
 
 struct lttng_transport {
@@ -592,9 +630,7 @@ int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
 
 int lttng_attach_context(struct lttng_ust_context *context_param,
                struct lttng_ctx **ctx, struct lttng_session *session);
-void lttng_context_init(void);
-void lttng_context_exit(void);
-extern struct lttng_ctx *lttng_static_ctx;     /* Used by filtering */
+int lttng_session_context_init(struct lttng_ctx **ctx);
 
 void lttng_transport_register(struct lttng_transport *transport);
 void lttng_transport_unregister(struct lttng_transport *transport);
@@ -619,6 +655,7 @@ int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx);
 int lttng_add_procname_to_ctx(struct lttng_ctx **ctx);
 int lttng_add_ip_to_ctx(struct lttng_ctx **ctx);
 int lttng_add_cpu_id_to_ctx(struct lttng_ctx **ctx);
+int lttng_add_dyntest_to_ctx(struct lttng_ctx **ctx);
 void lttng_context_vtid_reset(void);
 void lttng_context_vpid_reset(void);
 
index aa8b50f86e5a44aa055a72f3e89e46772efe8c10..f96239e0a9844262f1d767415eeca87e9a00fc89 100644 (file)
@@ -663,9 +663,10 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));      \
 static                                                                       \
 void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))              \
 {                                                                            \
-       struct lttng_event *__event = (struct lttng_event *) __tp_data;                       \
+       struct lttng_event *__event = (struct lttng_event *) __tp_data;       \
        struct lttng_channel *__chan = __event->chan;                         \
        struct lttng_ust_lib_ring_buffer_ctx __ctx;                           \
+       struct lttng_stack_ctx __lttng_ctx;                                   \
        size_t __event_len, __event_align;                                    \
        size_t __dynamic_len_idx = 0;                                         \
        union {                                                               \
@@ -703,8 +704,12 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))          \
        __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \
                 _TP_ARGS_DATA_VAR(_args));                                   \
        __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \
+       memset(&__lttng_ctx, 0, sizeof(__lttng_ctx));                         \
+       __lttng_ctx.event = __event;                                          \
+       __lttng_ctx.chan_ctx = tp_rcu_dereference_bp(__chan->ctx);            \
+       __lttng_ctx.event_ctx = tp_rcu_dereference_bp(__event->ctx);          \
        lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len,  \
-                                __event_align, -1, __chan->handle);          \
+                                __event_align, -1, __chan->handle, &__lttng_ctx); \
        __ctx.ip = _TP_IP_PARAM(TP_IP_PARAM);                                 \
        __ret = __chan->ops->event_reserve(&__ctx, __event->id);              \
        if (__ret < 0)                                                        \
index efebbb2a73f830eb5f86adb6c247c528ce89ab19..7f363d402f7c57b9e7ebc179acc29fc35b08970c 100644 (file)
@@ -260,6 +260,7 @@ int ustcomm_register_enum(int sock,
  * Returns -EPIPE or -ECONNRESET if other end has hung up.
  */
 int ustcomm_register_channel(int sock,
+       struct lttng_session *session,
        int session_objd,               /* session descriptor */
        int channel_objd,               /* channel descriptor */
        size_t nr_ctx_fields,
index 1a4419f52a98fbf5e51480b2810826bad9744166..2c54a443566a7fca4bc7e919d5bec6608f1fd176 100644 (file)
@@ -36,6 +36,7 @@
 #include <helper.h>
 #include <lttng/ust-error.h>
 #include <lttng/ust-events.h>
+#include <lttng/ust-dynamic-type.h>
 #include <usterr-signal-safe.h>
 
 #include "../liblttng-ust/compat.h"
 
 #define USTCOMM_MAX_SEND_FDS   4
 
+static
+ssize_t count_fields_recursive(size_t nr_fields,
+               const struct lttng_event_field *lttng_fields);
+static
+int serialize_one_field(struct lttng_session *session,
+               struct ustctl_field *fields, size_t *iter_output,
+               const struct lttng_event_field *lf);
+
 /*
  * Human readable error message.
  */
@@ -676,6 +685,86 @@ int ustcomm_send_reg_msg(int sock,
        return 0;
 }
 
+static
+ssize_t count_one_type(const struct lttng_type *lt)
+{
+       switch (lt->atype) {
+       case atype_integer:
+       case atype_float:
+       case atype_string:
+       case atype_enum:
+       case atype_array:
+       case atype_sequence:
+               return 1;
+       case atype_struct:
+               //TODO: implement non-empty struct.
+               return 1;
+       case atype_dynamic:
+       {
+               const struct lttng_event_field *choices;
+               size_t nr_choices;
+               int ret;
+
+               ret = lttng_ust_dynamic_type_choices(&nr_choices,
+                       &choices);
+               if (ret)
+                       return ret;
+               /*
+                * One field for enum, one field for variant, and
+                * one field per choice.
+                */
+               return count_fields_recursive(nr_choices, choices) + 2;
+       }
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+ssize_t count_fields_recursive(size_t nr_fields,
+               const struct lttng_event_field *lttng_fields)
+{
+       int i;
+       ssize_t ret, count = 0;
+
+       for (i = 0; i < nr_fields; i++) {
+               const struct lttng_event_field *lf;
+
+               lf = &lttng_fields[i];
+               /* skip 'nowrite' fields */
+               if (lf->nowrite)
+                       continue;
+               ret = count_one_type(&lf->type);
+               if (ret < 0)
+                       return ret;     /* error */
+               count += ret;
+       }
+       return count;
+}
+
+static
+ssize_t count_ctx_fields_recursive(size_t nr_fields,
+               const struct lttng_ctx_field *lttng_fields)
+{
+       int i;
+       ssize_t ret, count = 0;
+
+       for (i = 0; i < nr_fields; i++) {
+               const struct lttng_event_field *lf;
+
+               lf = &lttng_fields[i].event_field;
+               /* skip 'nowrite' fields */
+               if (lf->nowrite)
+                       continue;
+               ret = count_one_type(&lf->type);
+               if (ret < 0)
+                       return ret;     /* error */
+               count += ret;
+       }
+       return count;
+}
+
 static
 int serialize_string_encoding(enum ustctl_string_encodings *ue,
                enum lttng_string_encodings le)
@@ -778,27 +867,103 @@ int serialize_basic_type(struct lttng_session *session,
 }
 
 static
-int serialize_one_type(struct lttng_session *session,
-               struct ustctl_type *ut, const struct lttng_type *lt)
+int serialize_dynamic_type(struct lttng_session *session,
+               struct ustctl_field *fields, size_t *iter_output,
+               const struct lttng_event_field *lf)
 {
+       const struct lttng_event_field *choices;
+       char tag_field_name[LTTNG_UST_SYM_NAME_LEN];
+       const struct lttng_type *tag_type;
+       const struct lttng_event_field *tag_field_generic;
+       struct lttng_event_field tag_field = {
+               .name = tag_field_name,
+               .nowrite = 0,
+       };
+       struct ustctl_field *uf;
+       size_t nr_choices, i;
        int ret;
 
+       tag_field_generic = lttng_ust_dynamic_type_tag_field();
+       tag_type = &tag_field_generic->type;
+
+       /* Serialize enum field. */
+       strncpy(tag_field_name, lf->name, LTTNG_UST_SYM_NAME_LEN);
+       tag_field_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+       strncat(tag_field_name,
+               "_tag",
+               LTTNG_UST_SYM_NAME_LEN - strlen(tag_field_name) - 1);
+       tag_field.type = *tag_type;
+       ret = serialize_one_field(session, fields, iter_output,
+               &tag_field);
+       if (ret)
+               return ret;
+
+       /* Serialize variant field. */
+       uf = &fields[*iter_output];
+       ret = lttng_ust_dynamic_type_choices(&nr_choices, &choices);
+       if (ret)
+               return ret;
+
+       strncpy(uf->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
+       uf->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+       uf->type.atype = ustctl_atype_variant;
+       uf->type.u.variant.nr_choices = nr_choices;
+       strncpy(uf->type.u.variant.tag_name,
+               tag_field_name,
+               LTTNG_UST_SYM_NAME_LEN);
+       uf->type.u.variant.tag_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+       (*iter_output)++;
+
+       /* Serialize choice fields after variant. */
+       for (i = 0; i < nr_choices; i++) {
+               ret = serialize_one_field(session, fields,
+                       iter_output, &choices[i]);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static
+int serialize_one_field(struct lttng_session *session,
+               struct ustctl_field *fields, size_t *iter_output,
+               const struct lttng_event_field *lf)
+{
+       const struct lttng_type *lt = &lf->type;
+       int ret;
+
+       /* skip 'nowrite' fields */
+       if (lf->nowrite)
+               return 0;
+
        switch (lt->atype) {
        case atype_integer:
        case atype_float:
        case atype_string:
        case atype_enum:
+       {
+               struct ustctl_field *uf = &fields[*iter_output];
+               struct ustctl_type *ut = &uf->type;
+
+               strncpy(uf->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
+               uf->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
                ret = serialize_basic_type(session, &ut->atype, lt->atype,
                        &ut->u.basic, &lt->u.basic);
                if (ret)
                        return ret;
+               (*iter_output)++;
                break;
+       }
        case atype_array:
        {
+               struct ustctl_field *uf = &fields[*iter_output];
+               struct ustctl_type *ut = &uf->type;
                struct ustctl_basic_type *ubt;
                const struct lttng_basic_type *lbt;
-               int ret;
 
+               strncpy(uf->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
+               uf->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+               uf->type.atype = ustctl_atype_array;
                ubt = &ut->u.array.elem_type;
                lbt = &lt->u.array.elem_type;
                ut->u.array.length = lt->u.array.length;
@@ -807,14 +972,20 @@ int serialize_one_type(struct lttng_session *session,
                if (ret)
                        return -EINVAL;
                ut->atype = ustctl_atype_array;
+               (*iter_output)++;
                break;
        }
        case atype_sequence:
        {
+               struct ustctl_field *uf = &fields[*iter_output];
+               struct ustctl_type *ut = &uf->type;
                struct ustctl_basic_type *ubt;
                const struct lttng_basic_type *lbt;
                int ret;
 
+               strncpy(uf->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
+               uf->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+               uf->type.atype = ustctl_atype_sequence;
                ubt = &ut->u.sequence.length_type;
                lbt = &lt->u.sequence.length_type;
                ret = serialize_basic_type(session, &ubt->atype, lbt->atype,
@@ -828,6 +999,31 @@ int serialize_one_type(struct lttng_session *session,
                if (ret)
                        return -EINVAL;
                ut->atype = ustctl_atype_sequence;
+               (*iter_output)++;
+               break;
+       }
+       case atype_dynamic:
+       {
+               ret = serialize_dynamic_type(session, fields, iter_output, lf);
+               if (ret)
+                       return -EINVAL;
+               break;
+       }
+       case atype_struct:
+       {
+               struct ustctl_field *uf = &fields[*iter_output];
+
+               /*
+                * TODO: add support for non-empty struct.
+                */
+               if (lf->type.u._struct.nr_fields != 0) {
+                       return -EINVAL;
+               }
+               strncpy(uf->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
+               uf->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+               uf->type.atype = ustctl_atype_struct;
+               uf->type.u._struct.nr_fields = 0;
+               (*iter_output)++;
                break;
        }
        default:
@@ -844,29 +1040,24 @@ int serialize_fields(struct lttng_session *session,
                const struct lttng_event_field *lttng_fields)
 {
        struct ustctl_field *fields;
-       int i, ret;
-       size_t nr_write_fields = 0;
+       int ret;
+       size_t i, iter_output = 0;
+       ssize_t nr_write_fields;
+
+       nr_write_fields = count_fields_recursive(nr_fields, lttng_fields);
+       if (nr_write_fields < 0) {
+               return (int) nr_write_fields;
+       }
 
-       fields = zmalloc(nr_fields * sizeof(*fields));
+       fields = zmalloc(nr_write_fields * sizeof(*fields));
        if (!fields)
                return -ENOMEM;
 
        for (i = 0; i < nr_fields; i++) {
-               struct ustctl_field *f;
-               const struct lttng_event_field *lf;
-
-               f = &fields[nr_write_fields];
-               lf = &lttng_fields[i];
-
-               /* skip 'nowrite' fields */
-               if (lf->nowrite)
-                       continue;
-               strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
-               f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
-               ret = serialize_one_type(session, &f->type, &lf->type);
+               ret = serialize_one_field(session, fields, &iter_output,
+                               &lttng_fields[i]);
                if (ret)
                        goto error_type;
-               nr_write_fields++;
        }
 
        *_nr_write_fields = nr_write_fields;
@@ -907,35 +1098,32 @@ int serialize_entries(struct ustctl_enum_entry **_entries,
 }
 
 static
-int serialize_ctx_fields(size_t *_nr_write_fields,
+int serialize_ctx_fields(struct lttng_session *session,
+               size_t *_nr_write_fields,
                struct ustctl_field **ustctl_fields,
                size_t nr_fields,
                const struct lttng_ctx_field *lttng_fields)
 {
        struct ustctl_field *fields;
-       int i, ret;
-       size_t nr_write_fields = 0;
+       int ret;
+       size_t i, iter_output = 0;
+       ssize_t nr_write_fields;
 
-       fields = zmalloc(nr_fields * sizeof(*fields));
+       nr_write_fields = count_ctx_fields_recursive(nr_fields,
+                       lttng_fields);
+       if (nr_write_fields < 0) {
+               return (int) nr_write_fields;
+       }
+
+       fields = zmalloc(nr_write_fields * sizeof(*fields));
        if (!fields)
                return -ENOMEM;
 
        for (i = 0; i < nr_fields; i++) {
-               struct ustctl_field *f;
-               const struct lttng_event_field *lf;
-
-               f = &fields[nr_write_fields];
-               lf = &lttng_fields[i].event_field;
-
-               /* skip 'nowrite' fields */
-               if (lf->nowrite)
-                       continue;
-               strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
-               f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
-               ret = serialize_one_type(NULL, &f->type, &lf->type);
+               ret = serialize_one_field(session, fields, &iter_output,
+                               &lttng_fields[i].event_field);
                if (ret)
                        goto error_type;
-               nr_write_fields++;
        }
 
        *_nr_write_fields = nr_write_fields;
@@ -1198,6 +1386,7 @@ error_entries:
  * Returns -EPIPE or -ECONNRESET if other end has hung up.
  */
 int ustcomm_register_channel(int sock,
+       struct lttng_session *session,
        int session_objd,               /* session descriptor */
        int channel_objd,               /* channel descriptor */
        size_t nr_ctx_fields,
@@ -1226,7 +1415,7 @@ int ustcomm_register_channel(int sock,
 
        /* Calculate fields len, serialize fields. */
        if (nr_ctx_fields > 0) {
-               ret = serialize_ctx_fields(&nr_write_fields, &fields,
+               ret = serialize_ctx_fields(session, &nr_write_fields, &fields,
                                nr_ctx_fields, ctx_fields);
                if (ret)
                        return ret;
index 75b32fe527c8fa9d32af7c9f0be501ddb892045d..bbf47381e538d2021c2f3a57776549bd4de06f82 100644 (file)
@@ -1071,7 +1071,7 @@ int ustctl_write_metadata_to_channel(
                                chan->ops->packet_avail_size(chan->chan, chan->handle),
                                len - pos);
                lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len,
-                                        sizeof(char), -1, chan->handle);
+                                        sizeof(char), -1, chan->handle, NULL);
                /*
                 * We don't care about metadata buffer's records lost
                 * count, because we always retry here. Report error if
@@ -1118,7 +1118,7 @@ ssize_t ustctl_write_one_packet_to_channel(
                        chan->ops->packet_avail_size(chan->chan, chan->handle),
                        len);
        lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len,
-                       sizeof(char), -1, chan->handle);
+                       sizeof(char), -1, chan->handle, NULL);
        ret = chan->ops->event_reserve(&ctx, 0);
        if (ret != 0) {
                DBG("LTTng: event reservation failed");
index 698b4805ee800d7fef8fbd117958b0830da57858..876e9b5190d525ae722bf21c9f61709d48ba1635 100644 (file)
@@ -21,6 +21,7 @@ liblttng_ust_runtime_la_SOURCES = \
        lttng-ust-comm.c \
        lttng-ust-abi.c \
        lttng-probes.c \
+       lttng-context-provider.c \
        lttng-context-vtid.c \
        lttng-context-vpid.c \
        lttng-context-pthread-id.c \
@@ -62,6 +63,7 @@ liblttng_ust_support_la_SOURCES = \
        lttng-tracer.h \
        lttng-tracer-core.h \
        ust-core.c \
+       lttng-ust-dynamic-type.c \
        lttng-rb-clients.h \
        lttng-ring-buffer-client.h \
        lttng-ring-buffer-client-discard.c \
index fb6e407cfb9c1c82bdd9a2eb741e42bb0a8e7b02..840cafe7064d221aac7068e96fb3bb57252817e8 100644 (file)
@@ -35,7 +35,7 @@
 #include "../libringbuffer/getcpu.h"
 
 static
-size_t cpu_id_get_size(size_t offset)
+size_t cpu_id_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
@@ -58,12 +58,12 @@ void cpu_id_record(struct lttng_ctx_field *field,
 
 static
 void cpu_id_get_value(struct lttng_ctx_field *field,
-               union lttng_ctx_value *value)
+               struct lttng_ctx_value *value)
 {
        int cpu;
 
        cpu = lttng_ust_get_cpu();
-       value->s64 = cpu;
+       value->u.s64 = cpu;
 }
 
 int lttng_add_cpu_id_to_ctx(struct lttng_ctx **ctx)
index 31283f17199446d8542aed2c93d939effe620767..84c7349981fe6936d9c9cc29fa374fcdb725735e 100644 (file)
@@ -27,7 +27,7 @@
 #include <lttng/ringbuffer-config.h>
 
 static
-size_t ip_get_size(size_t offset)
+size_t ip_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
index 83b371c5ba91431f47f44ce6880a4087d2e0244c..97ddf977d1ba17706ae337bb66d3c1241da13038 100644 (file)
@@ -69,7 +69,7 @@ struct lttng_perf_counter_field {
 static pthread_key_t perf_counter_key;
 
 static
-size_t perf_counter_get_size(size_t offset)
+size_t perf_counter_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
@@ -280,12 +280,12 @@ void perf_counter_record(struct lttng_ctx_field *field,
 
 static
 void perf_counter_get_value(struct lttng_ctx_field *field,
-               union lttng_ctx_value *value)
+               struct lttng_ctx_value *value)
 {
        uint64_t v;
 
        v = wrapper_perf_counter_read(field);
-       value->s64 = v;
+       value->u.s64 = v;
 }
 
 /* Called with UST lock held */
index 4d41593e17cb503286e1355cbc3f03c0166b4c81..13461a6878fded8e47bf10c902b054940d4c4c16 100644 (file)
@@ -55,7 +55,7 @@ void lttng_context_procname_reset(void)
 }
 
 static
-size_t procname_get_size(size_t offset)
+size_t procname_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
@@ -76,12 +76,12 @@ void procname_record(struct lttng_ctx_field *field,
 
 static
 void procname_get_value(struct lttng_ctx_field *field,
-               union lttng_ctx_value *value)
+               struct lttng_ctx_value *value)
 {
        char *procname;
 
        procname = wrapper_getprocname();
-       value->str = procname;
+       value->u.str = procname;
 }
 
 int lttng_add_procname_to_ctx(struct lttng_ctx **ctx)
diff --git a/liblttng-ust/lttng-context-provider.c b/liblttng-ust/lttng-context-provider.c
new file mode 100644 (file)
index 0000000..e7462cd
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * lttng-context-provider.c
+ *
+ * LTTng UST application context provider.
+ *
+ * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <lttng/ust-context-provider.h>
+#include "lttng-tracer-core.h"
+#include "jhash.h"
+#include <helper.h>
+
+#define CONTEXT_PROVIDER_HT_BITS       12
+#define CONTEXT_PROVIDER_HT_SIZE       (1U << CONTEXT_PROVIDER_HT_BITS)
+struct context_provider_ht {
+       struct cds_hlist_head table[CONTEXT_PROVIDER_HT_SIZE];
+};
+
+static struct context_provider_ht context_provider_ht;
+
+static struct lttng_ust_context_provider *
+               lookup_provider_by_name(const char *name)
+{
+       struct cds_hlist_head *head;
+       struct cds_hlist_node *node;
+       struct lttng_ust_context_provider *provider;
+       uint32_t hash;
+       const char *end;
+       size_t len;
+
+       /* Lookup using everything before first ':' as key. */
+       end = strchr(name, ':');
+       if (end)
+               len = end - name;
+       else
+               len = strlen(name);
+       hash = jhash(name, len, 0);
+       head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)];
+       cds_hlist_for_each_entry(provider, node, head, node) {
+               if (!strncmp(provider->name, name, len))
+                       return provider;
+       }
+       return NULL;
+}
+
+int lttng_ust_context_provider_register(struct lttng_ust_context_provider *provider)
+{
+       struct cds_hlist_head *head;
+       size_t name_len = strlen(provider->name);
+       uint32_t hash;
+       int ret = 0;
+
+       /* Provider name starts with "$app.". */
+       if (strncmp("$app.", provider->name, strlen("$app.") != 0))
+               return -EINVAL;
+       /* Provider name cannot contain a column character. */
+       if (strchr(provider->name, ':'))
+               return -EINVAL;
+       if (ust_lock()) {
+               ret = -EBUSY;
+               goto end;
+       }
+       if (lookup_provider_by_name(provider->name)) {
+               ret = -EBUSY;
+               goto end;
+       }
+       hash = jhash(provider->name, name_len, 0);
+       head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)];
+       cds_hlist_add_head(&provider->node, head);
+       lttng_ust_context_set_session_provider(provider->name,
+               provider->get_size, provider->record,
+               provider->get_value);
+end:
+       ust_unlock();
+       return ret;
+}
+
+static
+size_t dummy_get_size(struct lttng_ctx_field *field, size_t offset)
+{
+       size_t size = 0;
+
+       size += lib_ring_buffer_align(offset, lttng_alignof(char));
+       size += sizeof(char);           /* tag */
+       return size;
+}
+
+static
+void dummy_record(struct lttng_ctx_field *field,
+                struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                struct lttng_channel *chan)
+{
+       char sel_char = (char) LTTNG_UST_DYNAMIC_TYPE_NONE;
+
+       lib_ring_buffer_align_ctx(ctx, lttng_alignof(sel_char));
+       chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+}
+
+static
+void dummy_get_value(struct lttng_ctx_field *field,
+               struct lttng_ctx_value *value)
+{
+       value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
+}
+
+void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider *provider)
+{
+       if (ust_lock())
+               goto end;
+       lttng_ust_context_set_session_provider(provider->name,
+               dummy_get_size, dummy_record, dummy_get_value);
+       cds_hlist_del(&provider->node);
+end:
+       ust_unlock();
+}
+
+/*
+ * Called with ust mutex held.
+ * Add application context to array of context, even if the application
+ * context is not currently loaded by application. It will then use the
+ * dummy callbacks in that case.
+ * Always performed before tracing is started, since it modifies
+ * metadata describing the context.
+ */
+int lttng_ust_add_app_context_to_ctx_rcu(const char *name,
+               struct lttng_ctx **ctx)
+{
+       struct lttng_ust_context_provider *provider;
+       struct lttng_ctx_field new_field;
+       int ret;
+
+       if (*ctx && lttng_find_context(*ctx, name))
+               return -EEXIST;
+       /*
+        * For application context, add it by expanding
+        * ctx array.
+        */
+       memset(&new_field, 0, sizeof(new_field));
+       new_field.field_name = strdup(name);
+       if (!new_field.field_name)
+               return -ENOMEM;
+       new_field.event_field.name = new_field.field_name;
+       new_field.event_field.type.atype = atype_dynamic;
+       /*
+        * If provider is not found, we add the context anyway, but
+        * it will provide a dummy context.
+        */
+       provider = lookup_provider_by_name(name);
+       if (provider) {
+               new_field.get_size = provider->get_size;
+               new_field.record = provider->record;
+               new_field.get_value = provider->get_value;
+       } else {
+               new_field.get_size = dummy_get_size;
+               new_field.record = dummy_record;
+               new_field.get_value = dummy_get_value;
+       }
+       ret = lttng_context_add_rcu(ctx, &new_field);
+       if (ret) {
+               free(new_field.field_name);
+               return ret;
+       }
+       return 0;
+}
index 2b90e7bc21ae5ab35c3179619b09437c7be5804d..c2c211574f2b6b21bd04d2b238aa523a70bf1022 100644 (file)
@@ -26,7 +26,7 @@
 #include <lttng/ringbuffer-config.h>
 
 static
-size_t pthread_id_get_size(size_t offset)
+size_t pthread_id_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
@@ -49,12 +49,12 @@ void pthread_id_record(struct lttng_ctx_field *field,
 
 static
 void pthread_id_get_value(struct lttng_ctx_field *field,
-               union lttng_ctx_value *value)
+               struct lttng_ctx_value *value)
 {
        unsigned long pthread_id;
 
        pthread_id = (unsigned long) pthread_self();
-       value->s64 = pthread_id;
+       value->u.s64 = pthread_id;
 }
 
 int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx)
index b54ada1dd1a0ef953e9025f05f86239237bae582..7d8091be0351052e3db95602dd839bd7a5d95406 100644 (file)
@@ -62,7 +62,7 @@ void lttng_context_vpid_reset(void)
 #endif
 
 static
-size_t vpid_get_size(size_t offset)
+size_t vpid_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
@@ -85,12 +85,12 @@ void vpid_record(struct lttng_ctx_field *field,
 
 static
 void vpid_get_value(struct lttng_ctx_field *field,
-               union lttng_ctx_value *value)
+               struct lttng_ctx_value *value)
 {
        pid_t pid;
 
        pid = wrapper_getpid();
-       value->s64 = pid;
+       value->u.s64 = pid;
 }
 
 int lttng_add_vpid_to_ctx(struct lttng_ctx **ctx)
index f9abadbb8f58eb1f05ee5bc22a3a49a509776b88..d1c73d8d6cf3ee0666522824e46f4a6265244e2e 100644 (file)
@@ -46,7 +46,7 @@ void lttng_context_vtid_reset(void)
 }
 
 static
-size_t vtid_get_size(size_t offset)
+size_t vtid_get_size(struct lttng_ctx_field *field, size_t offset)
 {
        size_t size = 0;
 
@@ -69,11 +69,11 @@ void vtid_record(struct lttng_ctx_field *field,
 
 static
 void vtid_get_value(struct lttng_ctx_field *field,
-               union lttng_ctx_value *value)
+               struct lttng_ctx_value *value)
 {
        if (caa_unlikely(!URCU_TLS(cached_vtid)))
                URCU_TLS(cached_vtid) = gettid();
-       value->s64 = URCU_TLS(cached_vtid);
+       value->u.s64 = URCU_TLS(cached_vtid);
 }
 
 int lttng_add_vtid_to_ctx(struct lttng_ctx **ctx)
index 199ec5d578f739c8ae108a16f0c89791e1636ec0..e2032162e514c8e1aac85e6ee88a13c559cc0cb8 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <lttng/ust-events.h>
 #include <lttng/ust-tracer.h>
+#include <lttng/ust-context-provider.h>
+#include <urcu-pointer.h>
 #include <usterr-signal-safe.h>
 #include <helper.h>
 #include <string.h>
  * same context performed by the same thread return the same result.
  */
 
-/*
- * Static array of contexts, for $ctx filters.
- */
-struct lttng_ctx *lttng_static_ctx;
-
 int lttng_find_context(struct lttng_ctx *ctx, const char *name)
 {
        unsigned int i;
+       const char *subname;
 
+       if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
+               subname = name + strlen("$ctx.");
+       } else {
+               subname = name;
+       }
        for (i = 0; i < ctx->nr_fields; i++) {
                /* Skip allocated (but non-initialized) contexts */
                if (!ctx->fields[i].event_field.name)
                        continue;
-               if (!strcmp(ctx->fields[i].event_field.name, name))
+               if (!strcmp(ctx->fields[i].event_field.name, subname))
                        return 1;
        }
        return 0;
 }
 
+int lttng_context_is_app(const char *name)
+{
+       if (strncmp(name, "$app.", strlen("$app.")) != 0) {
+               return 0;
+       }
+       return 1;
+}
+
 int lttng_get_context_index(struct lttng_ctx *ctx, const char *name)
 {
        unsigned int i;
+       const char *subname;
 
        if (!ctx)
                return -1;
+       if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
+               subname = name + strlen("$ctx.");
+       } else {
+               subname = name;
+       }
        for (i = 0; i < ctx->nr_fields; i++) {
                /* Skip allocated (but non-initialized) contexts */
                if (!ctx->fields[i].event_field.name)
                        continue;
-               if (!strcmp(ctx->fields[i].event_field.name, name))
+               if (!strcmp(ctx->fields[i].event_field.name, subname))
                        return i;
        }
        return -1;
 }
 
+static int lttng_find_context_provider(struct lttng_ctx *ctx, const char *name)
+{
+       unsigned int i;
+
+       for (i = 0; i < ctx->nr_fields; i++) {
+               /* Skip allocated (but non-initialized) contexts */
+               if (!ctx->fields[i].event_field.name)
+                       continue;
+               if (!strncmp(ctx->fields[i].event_field.name, name,
+                               strlen(name)))
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Note: as we append context information, the pointer location may change.
  */
@@ -100,6 +132,45 @@ struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p)
        return field;
 }
 
+int lttng_context_add_rcu(struct lttng_ctx **ctx_p,
+               const struct lttng_ctx_field *f)
+{
+       struct lttng_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
+       struct lttng_ctx_field *new_fields = NULL;
+       struct lttng_ctx_field *nf;
+
+       if (old_ctx) {
+               new_ctx = zmalloc(sizeof(struct lttng_ctx));
+               if (!new_ctx)
+                       return -ENOMEM;
+               *new_ctx = *old_ctx;
+               new_fields = zmalloc(new_ctx->allocated_fields
+                               * sizeof(struct lttng_ctx_field));
+               if (!new_fields) {
+                       free(new_ctx);
+                       return -ENOMEM;
+               }
+               memcpy(new_fields, old_ctx->fields,
+                               sizeof(*old_ctx->fields) * old_ctx->nr_fields);
+               new_ctx->fields = new_fields;
+       }
+       nf = lttng_append_context(&new_ctx);
+       if (!nf) {
+               free(new_fields);
+               free(new_ctx);
+               return -ENOMEM;
+       }
+       *nf = *f;
+       lttng_context_update(new_ctx);
+       rcu_assign_pointer(*ctx_p, new_ctx);
+       synchronize_trace();
+       if (old_ctx) {
+               free(old_ctx->fields);
+               free(old_ctx);
+       }
+       return 0;
+}
+
 /*
  * lttng_context_update() should be called at least once between context
  * modification and trace start.
@@ -177,7 +248,8 @@ void lttng_context_update(struct lttng_ctx *ctx)
                }
                case atype_string:
                        break;
-
+               case atype_dynamic:
+                       break;
                case atype_enum:
                default:
                        WARN_ON_ONCE(1);
@@ -199,6 +271,7 @@ void lttng_remove_context_field(struct lttng_ctx **ctx_p,
        ctx = *ctx_p;
        ctx->nr_fields--;
        assert(&ctx->fields[ctx->nr_fields] == field);
+       assert(field->field_name == NULL);
        memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
 }
 
@@ -211,39 +284,106 @@ void lttng_destroy_context(struct lttng_ctx *ctx)
        for (i = 0; i < ctx->nr_fields; i++) {
                if (ctx->fields[i].destroy)
                        ctx->fields[i].destroy(&ctx->fields[i]);
+               free(ctx->fields[i].field_name);
        }
        free(ctx->fields);
        free(ctx);
 }
 
-void lttng_context_init(void)
+/*
+ * Can be safely performed concurrently with tracing using the struct
+ * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
+ * contexts.
+ *
+ * This does not allow adding, removing, or changing typing of the
+ * contexts, since this needs to stay invariant for metadata. However,
+ * it allows updating the handlers associated with all contexts matching
+ * a provider (by name) while tracing is using it, in a way that ensures
+ * a single RCU read-side critical section see either all old, or all
+ * new handlers.
+ */
+int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
+               const char *name,
+               size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+               void (*record)(struct lttng_ctx_field *field,
+                       struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                       struct lttng_channel *chan),
+               void (*get_value)(struct lttng_ctx_field *field,
+                       struct lttng_ctx_value *value))
+{
+       int i, ret;
+       struct lttng_ctx *ctx = *_ctx, *new_ctx;
+       struct lttng_ctx_field *new_fields;
+
+       if (!ctx || !lttng_find_context_provider(ctx, name))
+               return 0;
+       /*
+        * We have at least one instance of context for the provider.
+        */
+       new_ctx = zmalloc(sizeof(*new_ctx));
+       if (!new_ctx)
+               return -ENOMEM;
+       *new_ctx = *ctx;
+       new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
+       if (!new_fields) {
+               ret = -ENOMEM;
+               goto field_error;
+       }
+       memcpy(new_fields, ctx->fields,
+               sizeof(*new_fields) * ctx->allocated_fields);
+       for (i = 0; i < ctx->nr_fields; i++) {
+               if (strncmp(new_fields[i].event_field.name,
+                               name, strlen(name)) != 0)
+                       continue;
+               new_fields[i].get_size = get_size;
+               new_fields[i].record = record;
+               new_fields[i].get_value = get_value;
+       }
+       new_ctx->fields = new_fields;
+       rcu_assign_pointer(*_ctx, new_ctx);
+       synchronize_trace();
+       free(ctx->fields);
+       free(ctx);
+       return 0;
+
+field_error:
+       free(new_ctx);
+       return ret;
+}
+
+int lttng_session_context_init(struct lttng_ctx **ctx)
 {
        int ret;
 
-       ret = lttng_add_pthread_id_to_ctx(&lttng_static_ctx);
+       ret = lttng_add_pthread_id_to_ctx(ctx);
        if (ret) {
                WARN("Cannot add context lttng_add_pthread_id_to_ctx");
+               goto error;
        }
-       ret = lttng_add_vtid_to_ctx(&lttng_static_ctx);
+       ret = lttng_add_vtid_to_ctx(ctx);
        if (ret) {
                WARN("Cannot add context lttng_add_vtid_to_ctx");
+               goto error;
        }
-       ret = lttng_add_vpid_to_ctx(&lttng_static_ctx);
+       ret = lttng_add_vpid_to_ctx(ctx);
        if (ret) {
                WARN("Cannot add context lttng_add_vpid_to_ctx");
+               goto error;
        }
-       ret = lttng_add_procname_to_ctx(&lttng_static_ctx);
+       ret = lttng_add_procname_to_ctx(ctx);
        if (ret) {
                WARN("Cannot add context lttng_add_procname_to_ctx");
+               goto error;
        }
-       ret = lttng_add_cpu_id_to_ctx(&lttng_static_ctx);
+       ret = lttng_add_cpu_id_to_ctx(ctx);
        if (ret) {
                WARN("Cannot add context lttng_add_cpu_id_to_ctx");
+               goto error;
        }
-}
+       lttng_context_update(*ctx);
+       return 0;
 
-void lttng_context_exit(void)
-{
-       lttng_destroy_context(lttng_static_ctx);
-       lttng_static_ctx = NULL;
+error:
+       lttng_destroy_context(*ctx);
+       return ret;
 }
index eb85b50d24e4e09ec128cf0ebd8f407e8f293623..f6db6e8a351d495e3e9cd2626e14fece8c21af49 100644 (file)
@@ -47,6 +47,8 @@
 #include <helper.h>
 #include <lttng/ust-ctl.h>
 #include <ust-comm.h>
+#include <lttng/ust-dynamic-type.h>
+#include <lttng/ust-context-provider.h>
 #include "error.h"
 #include "compat.h"
 #include "lttng-ust-uuid.h"
@@ -138,6 +140,10 @@ struct lttng_session *lttng_session_create(void)
        session = zmalloc(sizeof(struct lttng_session));
        if (!session)
                return NULL;
+       if (lttng_session_context_init(&session->ctx)) {
+               free(session);
+               return NULL;
+       }
        CDS_INIT_LIST_HEAD(&session->chan_head);
        CDS_INIT_LIST_HEAD(&session->events_head);
        CDS_INIT_LIST_HEAD(&session->enums_head);
@@ -236,9 +242,149 @@ void lttng_session_destroy(struct lttng_session *session)
        cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node)
                _lttng_channel_unmap(chan);
        cds_list_del(&session->node);
+       lttng_destroy_context(session->ctx);
        free(session);
 }
 
+static
+int lttng_enum_create(const struct lttng_enum_desc *desc,
+               struct lttng_session *session)
+{
+       const char *enum_name = desc->name;
+       struct lttng_enum *_enum;
+       struct cds_hlist_head *head;
+       struct cds_hlist_node *node;
+       int ret = 0;
+       size_t name_len = strlen(enum_name);
+       uint32_t hash;
+       int notify_socket;
+
+       hash = jhash(enum_name, name_len, 0);
+       head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)];
+       cds_hlist_for_each_entry(_enum, node, head, hlist) {
+               assert(_enum->desc);
+               if (!strncmp(_enum->desc->name, desc->name,
+                               LTTNG_UST_SYM_NAME_LEN - 1)) {
+                       ret = -EEXIST;
+                       goto exist;
+               }
+       }
+
+       notify_socket = lttng_get_notify_socket(session->owner);
+       if (notify_socket < 0) {
+               ret = notify_socket;
+               goto socket_error;
+       }
+
+       _enum = zmalloc(sizeof(*_enum));
+       if (!_enum) {
+               ret = -ENOMEM;
+               goto cache_error;
+       }
+       _enum->session = session;
+       _enum->desc = desc;
+
+       ret = ustcomm_register_enum(notify_socket,
+               session->objd,
+               enum_name,
+               desc->nr_entries,
+               desc->entries,
+               &_enum->id);
+       if (ret < 0) {
+               DBG("Error (%d) registering enumeration to sessiond", ret);
+               goto sessiond_register_error;
+       }
+       cds_list_add(&_enum->node, &session->enums_head);
+       cds_hlist_add_head(&_enum->hlist, head);
+       return 0;
+
+sessiond_register_error:
+       free(_enum);
+cache_error:
+socket_error:
+exist:
+       return ret;
+}
+
+static
+int lttng_create_enum_check(const struct lttng_type *type,
+               struct lttng_session *session)
+{
+       switch (type->atype) {
+       case atype_enum:
+       {
+               const struct lttng_enum_desc *enum_desc;
+               int ret;
+
+               enum_desc = type->u.basic.enumeration.desc;
+               ret = lttng_enum_create(enum_desc, session);
+               if (ret && ret != -EEXIST) {
+                       DBG("Unable to create enum error: (%d)", ret);
+                       return ret;
+               }
+               break;
+       }
+       case atype_dynamic:
+       {
+               const struct lttng_event_field *tag_field_generic;
+               const struct lttng_enum_desc *enum_desc;
+               int ret;
+
+               tag_field_generic = lttng_ust_dynamic_type_tag_field();
+               enum_desc = tag_field_generic->type.u.basic.enumeration.desc;
+               ret = lttng_enum_create(enum_desc, session);
+               if (ret && ret != -EEXIST) {
+                       DBG("Unable to create enum error: (%d)", ret);
+                       return ret;
+               }
+               break;
+       }
+       default:
+               /* TODO: nested types when they become supported. */
+               break;
+       }
+       return 0;
+}
+
+static
+int lttng_create_all_event_enums(size_t nr_fields,
+               const struct lttng_event_field *event_fields,
+               struct lttng_session *session)
+{
+       size_t i;
+       int ret;
+
+       /* For each field, ensure enum is part of the session. */
+       for (i = 0; i < nr_fields; i++) {
+               const struct lttng_type *type = &event_fields[i].type;
+
+               ret = lttng_create_enum_check(type, session);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static
+int lttng_create_all_ctx_enums(size_t nr_fields,
+               const struct lttng_ctx_field *ctx_fields,
+               struct lttng_session *session)
+{
+       size_t i;
+       int ret;
+
+       /* For each field, ensure enum is part of the session. */
+       for (i = 0; i < nr_fields; i++) {
+               const struct lttng_type *type = &ctx_fields[i].event_field.type;
+
+               ret = lttng_create_enum_check(type, session);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+
 int lttng_session_enable(struct lttng_session *session)
 {
        int ret = 0;
@@ -274,8 +420,15 @@ int lttng_session_enable(struct lttng_session *session)
                if (ctx) {
                        nr_fields = ctx->nr_fields;
                        fields = ctx->fields;
+                       ret = lttng_create_all_ctx_enums(nr_fields, fields,
+                               session);
+                       if (ret < 0) {
+                               DBG("Error (%d) adding enum to session", ret);
+                               return ret;
+                       }
                }
                ret = ustcomm_register_channel(notify_socket,
+                       session,
                        session->objd,
                        chan->objd,
                        nr_fields,
@@ -358,101 +511,6 @@ end:
        return ret;
 }
 
-static
-int lttng_enum_create(const struct lttng_enum_desc *desc,
-               struct lttng_session *session)
-{
-       const char *enum_name = desc->name;
-       struct lttng_enum *_enum;
-       struct cds_hlist_head *head;
-       struct cds_hlist_node *node;
-       int ret = 0;
-       size_t name_len = strlen(enum_name);
-       uint32_t hash;
-       int notify_socket;
-
-       hash = jhash(enum_name, name_len, 0);
-       head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)];
-       cds_hlist_for_each_entry(_enum, node, head, hlist) {
-               assert(_enum->desc);
-               if (!strncmp(_enum->desc->name, desc->name,
-                               LTTNG_UST_SYM_NAME_LEN - 1)) {
-                       ret = -EEXIST;
-                       goto exist;
-               }
-       }
-
-       notify_socket = lttng_get_notify_socket(session->owner);
-       if (notify_socket < 0) {
-               ret = notify_socket;
-               goto socket_error;
-       }
-
-       _enum = zmalloc(sizeof(*_enum));
-       if (!_enum) {
-               ret = -ENOMEM;
-               goto cache_error;
-       }
-       _enum->session = session;
-       _enum->desc = desc;
-
-       ret = ustcomm_register_enum(notify_socket,
-               session->objd,
-               enum_name,
-               desc->nr_entries,
-               desc->entries,
-               &_enum->id);
-       if (ret < 0) {
-               DBG("Error (%d) registering enumeration to sessiond", ret);
-               goto sessiond_register_error;
-       }
-       cds_list_add(&_enum->node, &session->enums_head);
-       cds_hlist_add_head(&_enum->hlist, head);
-       return 0;
-
-sessiond_register_error:
-       free(_enum);
-cache_error:
-socket_error:
-exist:
-       return ret;
-}
-
-static
-int lttng_event_create_all_enums(const struct lttng_event_desc *desc,
-               struct lttng_session *session)
-{
-       unsigned int nr_fields, i;
-       const struct lttng_event_field *fields;
-
-       /* For each field, ensure enum is part of the session. */
-       nr_fields = desc->nr_fields;
-       fields = desc->fields;
-       for (i = 0; i < nr_fields; i++) {
-               const struct lttng_type *type = &fields[i].type;
-
-               switch (type->atype) {
-               case atype_enum:
-               {
-                       const struct lttng_enum_desc *enum_desc;
-                       int ret;
-
-                       enum_desc = type->u.basic.enumeration.desc;
-                       ret = lttng_enum_create(enum_desc, session);
-                       if (ret && ret != -EEXIST) {
-                               DBG("Unable to create enum error: (%d)", ret);
-                               return ret;
-                       }
-                       break;
-               }
-               default:
-                       /* TODO: nested types when they become supported. */
-                       continue;
-               }
-       }
-       return 0;
-}
-
 /*
  * Supports event creation while tracing session is active.
  */
@@ -489,7 +547,8 @@ int lttng_event_create(const struct lttng_event_desc *desc,
                goto socket_error;
        }
 
-       ret = lttng_event_create_all_enums(desc, session);
+       ret = lttng_create_all_event_enums(desc->nr_fields, desc->fields,
+                       session);
        if (ret < 0) {
                DBG("Error (%d) adding enum to session", ret);
                goto create_enum_error;
@@ -1067,3 +1126,44 @@ void lttng_session_lazy_sync_enablers(struct lttng_session *session)
                return;
        lttng_session_sync_enablers(session);
 }
+
+/*
+ * Update all sessions with the given app context.
+ * Called with ust lock held.
+ * This is invoked when an application context gets loaded/unloaded. It
+ * ensures the context callbacks are in sync with the application
+ * context (either app context callbacks, or dummy callbacks).
+ */
+void lttng_ust_context_set_session_provider(const char *name,
+               size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+               void (*record)(struct lttng_ctx_field *field,
+                       struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                       struct lttng_channel *chan),
+               void (*get_value)(struct lttng_ctx_field *field,
+                       struct lttng_ctx_value *value))
+{
+       struct lttng_session *session;
+
+       cds_list_for_each_entry(session, &sessions, node) {
+               struct lttng_channel *chan;
+               struct lttng_event *event;
+               int ret;
+
+               ret = lttng_ust_context_set_provider_rcu(&session->ctx,
+                               name, get_size, record, get_value);
+               if (ret)
+                       abort();
+               cds_list_for_each_entry(chan, &session->chan_head, node) {
+                       ret = lttng_ust_context_set_provider_rcu(&chan->ctx,
+                                       name, get_size, record, get_value);
+                       if (ret)
+                               abort();
+               }
+               cds_list_for_each_entry(event, &session->events_head, node) {
+                       ret = lttng_ust_context_set_provider_rcu(&event->ctx,
+                                       name, get_size, record, get_value);
+                       if (ret)
+                               abort();
+               }
+       }
+}
index df4add225dbb2585548b6bcb740a4aaa026772b8..1f95dcf576b1c84fe53455ae3cc2fcf6b98187cb 100644 (file)
@@ -20,6 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <urcu-pointer.h>
 #include "lttng-filter.h"
 
 /*
@@ -136,13 +137,17 @@ uint64_t lttng_filter_false(void *filter_data,
                        (unsigned int) *(filter_opcode_t *) pc);        \
                switch (*(filter_opcode_t *) pc)        {
 
-#define OP(name)       case name
+#define OP(name)       jump_target_##name: __attribute__((unused));    \
+                       case name
 
 #define PO             break
 
 #define END_OP         }                                               \
        }
 
+#define JUMP_TO(name)                                                  \
+                       goto jump_target_##name
+
 #else
 
 /*
@@ -165,6 +170,9 @@ LABEL_##name
 
 #define END_OP
 
+#define JUMP_TO(name)                                                  \
+               goto LABEL_##name
+
 #endif
 
 /*
@@ -176,12 +184,14 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                const char *filter_stack_data)
 {
        struct bytecode_runtime *bytecode = filter_data;
+       struct lttng_session *session = bytecode->p.session;
        void *pc, *next_pc, *start_pc;
        int ret = -EINVAL;
        uint64_t retval = 0;
        struct estack _stack;
        struct estack *stack = &_stack;
        register int64_t ax = 0, bx = 0;
+       register enum entry_type ax_t = REG_UNKNOWN, bx_t = REG_UNKNOWN;
        register int top = FILTER_STACK_EMPTY;
 #ifndef INTERPRETER_USE_SWITCH
        static void *dispatch[NR_FILTER_OPS] = {
@@ -292,7 +302,6 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
 
                OP(FILTER_OP_UNKNOWN):
                OP(FILTER_OP_LOAD_FIELD_REF):
-               OP(FILTER_OP_GET_CONTEXT_REF):
 #ifdef INTERPRETER_USE_SWITCH
                default:
 #endif /* INTERPRETER_USE_SWITCH */
@@ -324,23 +333,362 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        goto end;
 
                OP(FILTER_OP_EQ):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_EQ_S64);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_EQ_DOUBLE_S64);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_DOUBLE:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_EQ_S64_DOUBLE);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_EQ_DOUBLE);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_STRING:
+                               switch (estack_bx_t) {
+                               case REG_S64:   /* Fall-through */
+                               case REG_DOUBLE:
+                                       ret = -EINVAL;
+                                       goto end;
+                               case REG_STRING:
+                                       JUMP_TO(FILTER_OP_EQ_STRING);
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_NE):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_NE_S64);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_NE_DOUBLE_S64);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_DOUBLE:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_NE_S64_DOUBLE);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_NE_DOUBLE);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_STRING:
+                               switch (estack_bx_t) {
+                               case REG_S64:   /* Fall-through */
+                               case REG_DOUBLE:
+                                       ret = -EINVAL;
+                                       goto end;
+                               case REG_STRING:
+                                       JUMP_TO(FILTER_OP_NE_STRING);
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_GT):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_GT_S64);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_GT_DOUBLE_S64);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_DOUBLE:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_GT_S64_DOUBLE);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_GT_DOUBLE);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_STRING:
+                               switch (estack_bx_t) {
+                               case REG_S64:   /* Fall-through */
+                               case REG_DOUBLE:
+                                       ret = -EINVAL;
+                                       goto end;
+                               case REG_STRING:
+                                       JUMP_TO(FILTER_OP_GT_STRING);
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_LT):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_LT_S64);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_LT_DOUBLE_S64);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_DOUBLE:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_LT_S64_DOUBLE);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_LT_DOUBLE);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_STRING:
+                               switch (estack_bx_t) {
+                               case REG_S64:   /* Fall-through */
+                               case REG_DOUBLE:
+                                       ret = -EINVAL;
+                                       goto end;
+                               case REG_STRING:
+                                       JUMP_TO(FILTER_OP_LT_STRING);
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_GE):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_GE_S64);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_GE_DOUBLE_S64);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_DOUBLE:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_GE_S64_DOUBLE);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_GE_DOUBLE);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_STRING:
+                               switch (estack_bx_t) {
+                               case REG_S64:   /* Fall-through */
+                               case REG_DOUBLE:
+                                       ret = -EINVAL;
+                                       goto end;
+                               case REG_STRING:
+                                       JUMP_TO(FILTER_OP_GE_STRING);
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_LE):
-                       ERR("unsupported non-specialized bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_LE_S64);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_LE_DOUBLE_S64);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_DOUBLE:
+                               switch (estack_bx_t) {
+                               case REG_S64:
+                                       JUMP_TO(FILTER_OP_LE_S64_DOUBLE);
+                               case REG_DOUBLE:
+                                       JUMP_TO(FILTER_OP_LE_DOUBLE);
+                               case REG_STRING:
+                                       ret = -EINVAL;
+                                       goto end;
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       case REG_STRING:
+                               switch (estack_bx_t) {
+                               case REG_S64:   /* Fall-through */
+                               case REG_DOUBLE:
+                                       ret = -EINVAL;
+                                       goto end;
+                               case REG_STRING:
+                                       JUMP_TO(FILTER_OP_LE_STRING);
+                               default:
+                                       ERR("Unknown filter register type (%d)",
+                                               (int) estack_bx_t);
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               break;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
 
                OP(FILTER_OP_EQ_STRING):
                {
                        int res;
 
                        res = (stack_strcmp(stack, top, "==") == 0);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -349,8 +697,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (stack_strcmp(stack, top, "!=") != 0);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -359,8 +708,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (stack_strcmp(stack, top, ">") > 0);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -369,8 +719,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (stack_strcmp(stack, top, "<") < 0);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -379,8 +730,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (stack_strcmp(stack, top, ">=") >= 0);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -389,8 +741,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (stack_strcmp(stack, top, "<=") <= 0);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -400,8 +753,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v == estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -410,8 +764,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v != estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -420,8 +775,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v > estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -430,8 +786,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v < estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -440,8 +797,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v >= estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -450,8 +808,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v <= estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -461,8 +820,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d == estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -471,8 +831,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d != estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -481,8 +842,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d > estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -491,8 +853,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d < estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -501,8 +864,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d >= estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -511,8 +875,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d <= estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -523,8 +888,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d == estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -533,8 +899,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d != estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -543,8 +910,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d > estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -553,8 +921,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d < estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -563,8 +932,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d >= estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -573,8 +943,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx(stack, top)->u.d <= estack_ax_v);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -584,8 +955,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v == estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -594,8 +966,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v != estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -604,8 +977,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v > estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -614,8 +988,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v < estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -624,8 +999,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v >= estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
@@ -634,21 +1010,70 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        int res;
 
                        res = (estack_bx_v <= estack_ax(stack, top)->u.d);
-                       estack_pop(stack, top, ax, bx);
+                       estack_pop(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = res;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct binary_op);
                        PO;
                }
 
                /* unary */
                OP(FILTER_OP_UNARY_PLUS):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:   /* Fall-through. */
+                               JUMP_TO(FILTER_OP_UNARY_PLUS_S64);
+                       case REG_DOUBLE:
+                               JUMP_TO(FILTER_OP_UNARY_PLUS_DOUBLE);
+                       case REG_STRING:
+                               ret = -EINVAL;
+                               goto end;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_UNARY_MINUS):
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               JUMP_TO(FILTER_OP_UNARY_MINUS_S64);
+                       case REG_DOUBLE:
+                               JUMP_TO(FILTER_OP_UNARY_MINUS_DOUBLE);
+                       case REG_STRING:
+                               ret = -EINVAL;
+                               goto end;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
                OP(FILTER_OP_UNARY_NOT):
-                       ERR("unsupported non-specialized bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
-
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               JUMP_TO(FILTER_OP_UNARY_NOT_S64);
+                       case REG_DOUBLE:
+                               JUMP_TO(FILTER_OP_UNARY_NOT_DOUBLE);
+                       case REG_STRING:
+                               ret = -EINVAL;
+                               goto end;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+                       next_pc += sizeof(struct unary_op);
+                       PO;
+               }
 
                OP(FILTER_OP_UNARY_PLUS_S64):
                OP(FILTER_OP_UNARY_PLUS_DOUBLE):
@@ -676,7 +1101,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                }
                OP(FILTER_OP_UNARY_NOT_DOUBLE):
                {
-                       estack_ax(stack, top)->u.d = !estack_ax(stack, top)->u.d;
+                       estack_ax_v = !estack_ax(stack, top)->u.d;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct unary_op);
                        PO;
                }
@@ -686,6 +1112,10 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                {
                        struct logical_op *insn = (struct logical_op *) pc;
 
+                       if (estack_ax_t != REG_S64) {
+                               ret = -EINVAL;
+                               goto end;
+                       }
                        /* If AX is 0, skip and evaluate to 0 */
                        if (unlikely(estack_ax_v == 0)) {
                                dbg_printf("Jumping to bytecode offset %u\n",
@@ -693,7 +1123,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                                next_pc = start_pc + insn->skip_offset;
                        } else {
                                /* Pop 1 when jump not taken */
-                               estack_pop(stack, top, ax, bx);
+                               estack_pop(stack, top, ax, bx, ax_t, bx_t);
                                next_pc += sizeof(struct logical_op);
                        }
                        PO;
@@ -702,8 +1132,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                {
                        struct logical_op *insn = (struct logical_op *) pc;
 
+                       if (estack_ax_t != REG_S64) {
+                               ret = -EINVAL;
+                               goto end;
+                       }
                        /* If AX is nonzero, skip and evaluate to 1 */
-
                        if (unlikely(estack_ax_v != 0)) {
                                estack_ax_v = 1;
                                dbg_printf("Jumping to bytecode offset %u\n",
@@ -711,7 +1144,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                                next_pc = start_pc + insn->skip_offset;
                        } else {
                                /* Pop 1 when jump not taken */
-                               estack_pop(stack, top, ax, bx);
+                               estack_pop(stack, top, ax, bx, ax_t, bx_t);
                                next_pc += sizeof(struct logical_op);
                        }
                        PO;
@@ -726,7 +1159,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
 
                        dbg_printf("load field ref offset %u type string\n",
                                ref->offset);
-                       estack_push(stack, top, ax, bx);
+                       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];
                        if (unlikely(!estack_ax(stack, top)->u.s.str)) {
@@ -736,6 +1169,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        }
                        estack_ax(stack, top)->u.s.seq_len = UINT_MAX;
                        estack_ax(stack, top)->u.s.literal = 0;
+                       estack_ax_t = REG_STRING;
                        dbg_printf("ref load string %s\n", estack_ax(stack, top)->u.s.str);
                        next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
                        PO;
@@ -748,12 +1182,13 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
 
                        dbg_printf("load field ref offset %u type sequence\n",
                                ref->offset);
-                       estack_push(stack, top, ax, bx);
+                       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];
                        estack_ax(stack, top)->u.s.str =
                                *(const char **) (&filter_stack_data[ref->offset
                                                                + sizeof(unsigned long)]);
+                       estack_ax_t = REG_STRING;
                        if (unlikely(!estack_ax(stack, top)->u.s.str)) {
                                dbg_printf("Filter warning: loading a NULL sequence.\n");
                                ret = -EINVAL;
@@ -771,9 +1206,10 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
 
                        dbg_printf("load field ref offset %u type s64\n",
                                ref->offset);
-                       estack_push(stack, top, ax, bx);
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v =
                                ((struct literal_numeric *) &filter_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);
                        PO;
@@ -786,9 +1222,10 @@ 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);
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
                        memcpy(&estack_ax(stack, top)->u.d, &filter_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);
                        next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
                        PO;
@@ -800,10 +1237,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        struct load_op *insn = (struct load_op *) pc;
 
                        dbg_printf("load string %s\n", insn->data);
-                       estack_push(stack, top, ax, bx);
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax(stack, top)->u.s.str = insn->data;
                        estack_ax(stack, top)->u.s.seq_len = UINT_MAX;
                        estack_ax(stack, top)->u.s.literal = 1;
+                       estack_ax_t = REG_STRING;
                        next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
                        PO;
                }
@@ -812,8 +1250,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                {
                        struct load_op *insn = (struct load_op *) pc;
 
-                       estack_push(stack, top, ax, bx);
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
                        estack_ax_v = ((struct literal_numeric *) insn->data)->v;
+                       estack_ax_t = REG_S64;
                        dbg_printf("load s64 %" PRIi64 "\n", estack_ax_v);
                        next_pc += sizeof(struct load_op)
                                        + sizeof(struct literal_numeric);
@@ -824,10 +1263,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                {
                        struct load_op *insn = (struct load_op *) pc;
 
-                       estack_push(stack, top, ax, bx);
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
                        memcpy(&estack_ax(stack, top)->u.d, insn->data,
                                sizeof(struct literal_double));
-                       dbg_printf("load s64 %g\n", estack_ax(stack, top)->u.d);
+                       estack_ax_t = REG_DOUBLE;
+                       dbg_printf("load double %g\n", estack_ax(stack, top)->u.d);
                        next_pc += sizeof(struct load_op)
                                        + sizeof(struct literal_double);
                        PO;
@@ -835,14 +1275,28 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
 
                /* cast */
                OP(FILTER_OP_CAST_TO_S64):
-                       ERR("unsupported non-specialized bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
+               {
+                       /* Dynamic typing. */
+                       switch (estack_ax_t) {
+                       case REG_S64:
+                               JUMP_TO(FILTER_OP_CAST_NOP);
+                       case REG_DOUBLE:
+                               JUMP_TO(FILTER_OP_CAST_DOUBLE_TO_S64);
+                       case REG_STRING:
+                               ret = -EINVAL;
+                               goto end;
+                       default:
+                               ERR("Unknown filter register type (%d)",
+                                       (int) estack_ax_t);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+               }
 
                OP(FILTER_OP_CAST_DOUBLE_TO_S64):
                {
                        estack_ax_v = (int64_t) estack_ax(stack, top)->u.d;
+                       estack_ax_t = REG_S64;
                        next_pc += sizeof(struct cast_op);
                        PO;
                }
@@ -854,19 +1308,70 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                }
 
                /* get context ref */
+               OP(FILTER_OP_GET_CONTEXT_REF):
+               {
+                       struct load_op *insn = (struct load_op *) pc;
+                       struct field_ref *ref = (struct field_ref *) insn->data;
+                       struct lttng_ctx *ctx;
+                       struct lttng_ctx_field *ctx_field;
+                       struct lttng_ctx_value v;
+
+                       dbg_printf("get context ref offset %u type dynamic\n",
+                               ref->offset);
+                       ctx = rcu_dereference(session->ctx);
+                       ctx_field = &ctx->fields[ref->offset];
+                       ctx_field->get_value(ctx_field, &v);
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
+                       switch (v.sel) {
+                       case LTTNG_UST_DYNAMIC_TYPE_NONE:
+                               ret = -EINVAL;
+                               goto end;
+                       case LTTNG_UST_DYNAMIC_TYPE_S64:
+                               estack_ax_v = v.u.s64;
+                               estack_ax_t = REG_S64;
+                               dbg_printf("ref get context dynamic s64 %" PRIi64 "\n", estack_ax_v);
+                               break;
+                       case LTTNG_UST_DYNAMIC_TYPE_DOUBLE:
+                               estack_ax(stack, top)->u.d = v.u.d;
+                               estack_ax_t = REG_DOUBLE;
+                               dbg_printf("ref get context dynamic double %g\n", estack_ax(stack, top)->u.d);
+                               break;
+                       case LTTNG_UST_DYNAMIC_TYPE_STRING:
+                               estack_ax(stack, top)->u.s.str = v.u.str;
+                               if (unlikely(!estack_ax(stack, top)->u.s.str)) {
+                                       dbg_printf("Filter warning: loading a NULL string.\n");
+                                       ret = -EINVAL;
+                                       goto end;
+                               }
+                               estack_ax(stack, top)->u.s.seq_len = UINT_MAX;
+                               estack_ax(stack, top)->u.s.literal = 0;
+                               dbg_printf("ref get context dynamic string %s\n", estack_ax(stack, top)->u.s.str);
+                               estack_ax_t = REG_STRING;
+                               break;
+                       default:
+                               dbg_printf("Filter warning: unknown dynamic type (%d).\n", (int) v.sel);
+                               ret = -EINVAL;
+                               goto end;
+                       }
+                       next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
+                       PO;
+               }
+
                OP(FILTER_OP_GET_CONTEXT_REF_STRING):
                {
                        struct load_op *insn = (struct load_op *) pc;
                        struct field_ref *ref = (struct field_ref *) insn->data;
+                       struct lttng_ctx *ctx;
                        struct lttng_ctx_field *ctx_field;
-                       union lttng_ctx_value v;
+                       struct lttng_ctx_value v;
 
                        dbg_printf("get context ref offset %u type string\n",
                                ref->offset);
-                       ctx_field = &lttng_static_ctx->fields[ref->offset];
+                       ctx = rcu_dereference(session->ctx);
+                       ctx_field = &ctx->fields[ref->offset];
                        ctx_field->get_value(ctx_field, &v);
-                       estack_push(stack, top, ax, bx);
-                       estack_ax(stack, top)->u.s.str = v.str;
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
+                       estack_ax(stack, top)->u.s.str = v.u.str;
                        if (unlikely(!estack_ax(stack, top)->u.s.str)) {
                                dbg_printf("Filter warning: loading a NULL string.\n");
                                ret = -EINVAL;
@@ -874,6 +1379,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                        }
                        estack_ax(stack, top)->u.s.seq_len = UINT_MAX;
                        estack_ax(stack, top)->u.s.literal = 0;
+                       estack_ax_t = REG_STRING;
                        dbg_printf("ref get context string %s\n", estack_ax(stack, top)->u.s.str);
                        next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
                        PO;
@@ -883,15 +1389,18 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                {
                        struct load_op *insn = (struct load_op *) pc;
                        struct field_ref *ref = (struct field_ref *) insn->data;
+                       struct lttng_ctx *ctx;
                        struct lttng_ctx_field *ctx_field;
-                       union lttng_ctx_value v;
+                       struct lttng_ctx_value v;
 
                        dbg_printf("get context ref offset %u type s64\n",
                                ref->offset);
-                       ctx_field = &lttng_static_ctx->fields[ref->offset];
+                       ctx = rcu_dereference(session->ctx);
+                       ctx_field = &ctx->fields[ref->offset];
                        ctx_field->get_value(ctx_field, &v);
-                       estack_push(stack, top, ax, bx);
-                       estack_ax_v = v.s64;
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
+                       estack_ax_v = v.u.s64;
+                       estack_ax_t = REG_S64;
                        dbg_printf("ref get context s64 %" PRIi64 "\n", estack_ax_v);
                        next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
                        PO;
@@ -901,15 +1410,18 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data,
                {
                        struct load_op *insn = (struct load_op *) pc;
                        struct field_ref *ref = (struct field_ref *) insn->data;
+                       struct lttng_ctx *ctx;
                        struct lttng_ctx_field *ctx_field;
-                       union lttng_ctx_value v;
+                       struct lttng_ctx_value v;
 
                        dbg_printf("get context ref offset %u type double\n",
                                ref->offset);
-                       ctx_field = &lttng_static_ctx->fields[ref->offset];
+                       ctx = rcu_dereference(session->ctx);
+                       ctx_field = &ctx->fields[ref->offset];
                        ctx_field->get_value(ctx_field, &v);
-                       estack_push(stack, top, ax, bx);
-                       memcpy(&estack_ax(stack, top)->u.d, &v.d, sizeof(struct literal_double));
+                       estack_push(stack, top, ax, bx, ax_t, bx_t);
+                       memcpy(&estack_ax(stack, top)->u.d, &v.u.d, sizeof(struct literal_double));
+                       estack_ax_t = REG_DOUBLE;
                        dbg_printf("ref get context double %g\n", estack_ax(stack, top)->u.d);
                        next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
                        PO;
index a729e427f9dead2c3ebdaffc931f79cb9ff79b39..dddb448e43b192bdfd5b9cdbb26c480be17409c5 100644 (file)
@@ -73,20 +73,28 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                                goto end;
 
                        case REG_STRING:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                insn->op = FILTER_OP_EQ_STRING;
                                break;
                        case REG_S64:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_EQ_S64;
                                else
                                        insn->op = FILTER_OP_EQ_DOUBLE_S64;
                                break;
                        case REG_DOUBLE:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_EQ_S64_DOUBLE;
                                else
                                        insn->op = FILTER_OP_EQ_DOUBLE;
                                break;
+                       case REG_UNKNOWN:
+                               break;  /* Dynamic typing. */
                        }
                        /* Pop 2, push 1 */
                        if (vstack_pop(stack)) {
@@ -109,20 +117,28 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                                goto end;
 
                        case REG_STRING:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                insn->op = FILTER_OP_NE_STRING;
                                break;
                        case REG_S64:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_NE_S64;
                                else
                                        insn->op = FILTER_OP_NE_DOUBLE_S64;
                                break;
                        case REG_DOUBLE:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_NE_S64_DOUBLE;
                                else
                                        insn->op = FILTER_OP_NE_DOUBLE;
                                break;
+                       case REG_UNKNOWN:
+                               break;  /* Dynamic typing. */
                        }
                        /* Pop 2, push 1 */
                        if (vstack_pop(stack)) {
@@ -145,20 +161,28 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                                goto end;
 
                        case REG_STRING:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                insn->op = FILTER_OP_GT_STRING;
                                break;
                        case REG_S64:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_GT_S64;
                                else
                                        insn->op = FILTER_OP_GT_DOUBLE_S64;
                                break;
                        case REG_DOUBLE:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_GT_S64_DOUBLE;
                                else
                                        insn->op = FILTER_OP_GT_DOUBLE;
                                break;
+                       case REG_UNKNOWN:
+                               break;  /* Dynamic typing. */
                        }
                        /* Pop 2, push 1 */
                        if (vstack_pop(stack)) {
@@ -181,20 +205,28 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                                goto end;
 
                        case REG_STRING:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                insn->op = FILTER_OP_LT_STRING;
                                break;
                        case REG_S64:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_LT_S64;
                                else
                                        insn->op = FILTER_OP_LT_DOUBLE_S64;
                                break;
                        case REG_DOUBLE:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_LT_S64_DOUBLE;
                                else
                                        insn->op = FILTER_OP_LT_DOUBLE;
                                break;
+                       case REG_UNKNOWN:
+                               break;  /* Dynamic typing. */
                        }
                        /* Pop 2, push 1 */
                        if (vstack_pop(stack)) {
@@ -217,20 +249,28 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                                goto end;
 
                        case REG_STRING:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                insn->op = FILTER_OP_GE_STRING;
                                break;
                        case REG_S64:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_GE_S64;
                                else
                                        insn->op = FILTER_OP_GE_DOUBLE_S64;
                                break;
                        case REG_DOUBLE:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_GE_S64_DOUBLE;
                                else
                                        insn->op = FILTER_OP_GE_DOUBLE;
                                break;
+                       case REG_UNKNOWN:
+                               break;  /* Dynamic typing. */
                        }
                        /* Pop 2, push 1 */
                        if (vstack_pop(stack)) {
@@ -252,20 +292,28 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                                goto end;
 
                        case REG_STRING:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                insn->op = FILTER_OP_LE_STRING;
                                break;
                        case REG_S64:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_LE_S64;
                                else
                                        insn->op = FILTER_OP_LE_DOUBLE_S64;
                                break;
                        case REG_DOUBLE:
+                               if (vstack_bx(stack)->type == REG_UNKNOWN)
+                                       break;
                                if (vstack_bx(stack)->type == REG_S64)
                                        insn->op = FILTER_OP_LE_S64_DOUBLE;
                                else
                                        insn->op = FILTER_OP_LE_DOUBLE;
                                break;
+                       case REG_UNKNOWN:
+                               break;  /* Dynamic typing. */
                        }
                        vstack_ax(stack)->type = REG_S64;
                        next_pc += sizeof(struct binary_op);
@@ -330,6 +378,8 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                        case REG_DOUBLE:
                                insn->op = FILTER_OP_UNARY_PLUS_DOUBLE;
                                break;
+                       case REG_UNKNOWN:       /* Dynamic typing. */
+                               break;
                        }
                        /* Pop 1, push 1 */
                        next_pc += sizeof(struct unary_op);
@@ -352,6 +402,8 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                        case REG_DOUBLE:
                                insn->op = FILTER_OP_UNARY_MINUS_DOUBLE;
                                break;
+                       case REG_UNKNOWN:       /* Dynamic typing. */
+                               break;
                        }
                        /* Pop 1, push 1 */
                        next_pc += sizeof(struct unary_op);
@@ -374,6 +426,8 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                        case REG_DOUBLE:
                                insn->op = FILTER_OP_UNARY_NOT_DOUBLE;
                                break;
+                       case REG_UNKNOWN:       /* Dynamic typing. */
+                               break;
                        }
                        /* Pop 1, push 1 */
                        next_pc += sizeof(struct unary_op);
@@ -416,9 +470,13 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                /* get context ref */
                case FILTER_OP_GET_CONTEXT_REF:
                {
-                       ERR("Unknown get context ref type\n");
-                       ret = -EINVAL;
-                       goto end;
+                       if (vstack_push(stack)) {
+                               ret = -EINVAL;
+                               goto end;
+                       }
+                       vstack_ax(stack)->type = REG_UNKNOWN;
+                       next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
+                       break;
                }
                case FILTER_OP_LOAD_FIELD_REF_STRING:
                case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
@@ -514,6 +572,8 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
                        case REG_DOUBLE:
                                insn->op = FILTER_OP_CAST_DOUBLE_TO_S64;
                                break;
+                       case REG_UNKNOWN:
+                               break;
                        }
                        /* Pop 1, push 1 */
                        vstack_ax(stack)->type = REG_S64;
index 6cdfd8c164764e075bab11a5cb8234c51765890f..dc50774de5b6deb6c20efdcd9c7f3cc905b3bb07 100644 (file)
@@ -74,7 +74,9 @@ int merge_points_compare(const struct vstack *stacka,
        len = stacka->top + 1;
        assert(len >= 0);
        for (i = 0; i < len; i++) {
-               if (stacka->e[i].type != stackb->e[i].type)
+               if (stacka->e[i].type != REG_UNKNOWN
+                               && stackb->e[i].type != REG_UNKNOWN
+                               && stacka->e[i].type != stackb->e[i].type)
                        return 1;
        }
        return 0;
@@ -118,22 +120,28 @@ int merge_point_add_check(struct cds_lfht *ht, unsigned long target_pc,
 
 /*
  * Binary comparators use top of stack and top of stack -1.
+ * Return 0 if typing is known to match, 1 if typing is dynamic
+ * (unknown), negative error value on error.
  */
 static
 int bin_op_compare_check(struct vstack *stack, const char *str)
 {
        if (unlikely(!vstack_ax(stack) || !vstack_bx(stack)))
-               goto error_unknown;
+               goto error_empty;
 
        switch (vstack_ax(stack)->type) {
        default:
-               goto error_unknown;
+               goto error_type;
 
+       case REG_UNKNOWN:
+               goto unknown;
        case REG_STRING:
                switch (vstack_bx(stack)->type) {
                default:
-                       goto error_unknown;
+                       goto error_type;
 
+               case REG_UNKNOWN:
+                       goto unknown;
                case REG_STRING:
                        break;
                case REG_S64:
@@ -145,11 +153,12 @@ int bin_op_compare_check(struct vstack *stack, const char *str)
        case REG_DOUBLE:
                switch (vstack_bx(stack)->type) {
                default:
-                       goto error_unknown;
+                       goto error_type;
 
+               case REG_UNKNOWN:
+                       goto unknown;
                case REG_STRING:
                        goto error_mismatch;
-
                case REG_S64:
                case REG_DOUBLE:
                        break;
@@ -158,12 +167,20 @@ int bin_op_compare_check(struct vstack *stack, const char *str)
        }
        return 0;
 
-error_unknown:
-       return -EINVAL;
+unknown:
+       return 1;
 
 error_mismatch:
        ERR("type mismatch for '%s' binary operator\n", str);
        return -EINVAL;
+
+error_empty:
+       ERR("empty stack for '%s' binary operator\n", str);
+       return -EINVAL;
+
+error_type:
+       ERR("unknown type for '%s' binary operator\n", str);
+       return -EINVAL;
 }
 
 /*
@@ -295,11 +312,6 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode,
        }
        /* get context ref */
        case FILTER_OP_GET_CONTEXT_REF:
-       {
-               ERR("Unknown field ref type\n");
-               ret = -EINVAL;
-               break;
-       }
        case FILTER_OP_LOAD_FIELD_REF_STRING:
        case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
        case FILTER_OP_LOAD_FIELD_REF_S64:
@@ -391,7 +403,7 @@ unsigned long delete_all_nodes(struct cds_lfht *ht)
 
 /*
  * Return value:
- * 0: success
+ * >=0: success
  * <0: error
  */
 static
@@ -438,42 +450,42 @@ int validate_instruction_context(struct bytecode_runtime *bytecode,
        case FILTER_OP_EQ:
        {
                ret = bin_op_compare_check(stack, "==");
-               if (ret)
+               if (ret < 0)
                        goto end;
                break;
        }
        case FILTER_OP_NE:
        {
                ret = bin_op_compare_check(stack, "!=");
-               if (ret)
+               if (ret < 0)
                        goto end;
                break;
        }
        case FILTER_OP_GT:
        {
                ret = bin_op_compare_check(stack, ">");
-               if (ret)
+               if (ret < 0)
                        goto end;
                break;
        }
        case FILTER_OP_LT:
        {
                ret = bin_op_compare_check(stack, "<");
-               if (ret)
+               if (ret < 0)
                        goto end;
                break;
        }
        case FILTER_OP_GE:
        {
                ret = bin_op_compare_check(stack, ">=");
-               if (ret)
+               if (ret < 0)
                        goto end;
                break;
        }
        case FILTER_OP_LE:
        {
                ret = bin_op_compare_check(stack, "<=");
-               if (ret)
+               if (ret < 0)
                        goto end;
                break;
        }
@@ -604,6 +616,8 @@ int validate_instruction_context(struct bytecode_runtime *bytecode,
                        break;
                case REG_DOUBLE:
                        break;
+               case REG_UNKNOWN:
+                       break;
                }
                break;
        }
@@ -653,8 +667,9 @@ int validate_instruction_context(struct bytecode_runtime *bytecode,
                        ret = -EINVAL;
                        goto end;
                }
-               if (vstack_ax(stack)->type != REG_S64) {
-                       ERR("Logical comparator expects S64 register\n");
+               if (vstack_ax(stack)->type != REG_S64
+                               && vstack_ax(stack)->type != REG_UNKNOWN) {
+                       ERR("Logical comparator expects S64 or dynamic register\n");
                        ret = -EINVAL;
                        goto end;
                }
@@ -745,6 +760,8 @@ int validate_instruction_context(struct bytecode_runtime *bytecode,
                        break;
                case REG_DOUBLE:
                        break;
+               case REG_UNKNOWN:
+                       break;
                }
                if (insn->op == FILTER_OP_CAST_DOUBLE_TO_S64) {
                        if (vstack_ax(stack)->type != REG_DOUBLE) {
@@ -763,9 +780,12 @@ int validate_instruction_context(struct bytecode_runtime *bytecode,
        /* get context ref */
        case FILTER_OP_GET_CONTEXT_REF:
        {
-               ERR("Unknown get context ref type\n");
-               ret = -EINVAL;
-               goto end;
+               struct load_op *insn = (struct load_op *) pc;
+               struct field_ref *ref = (struct field_ref *) insn->data;
+
+               dbg_printf("Validate get context ref offset %u type dynamic\n",
+                       ref->offset);
+               break;
        }
        case FILTER_OP_GET_CONTEXT_REF_STRING:
        {
@@ -821,7 +841,7 @@ int validate_instruction_all_contexts(struct bytecode_runtime *bytecode,
 
        /* Validate the context resulting from the previous instruction */
        ret = validate_instruction_context(bytecode, stack, start_pc, pc);
-       if (ret)
+       if (ret < 0)
                return ret;
 
        /* Validate merge points */
@@ -959,10 +979,23 @@ int exec_insn(struct bytecode_runtime *bytecode,
        /* unary */
        case FILTER_OP_UNARY_PLUS:
        case FILTER_OP_UNARY_MINUS:
-       case FILTER_OP_UNARY_NOT:
+       {
+               /* Pop 1, push 1 */
+               if (!vstack_ax(stack)) {
+                       ERR("Empty stack\n");
+                       ret = -EINVAL;
+                       goto end;
+               }
+               vstack_ax(stack)->type = REG_UNKNOWN;
+               next_pc += sizeof(struct unary_op);
+               break;
+       }
+
        case FILTER_OP_UNARY_PLUS_S64:
        case FILTER_OP_UNARY_MINUS_S64:
+       case FILTER_OP_UNARY_NOT:
        case FILTER_OP_UNARY_NOT_S64:
+       case FILTER_OP_UNARY_NOT_DOUBLE:
        {
                /* Pop 1, push 1 */
                if (!vstack_ax(stack)) {
@@ -977,7 +1010,6 @@ int exec_insn(struct bytecode_runtime *bytecode,
 
        case FILTER_OP_UNARY_PLUS_DOUBLE:
        case FILTER_OP_UNARY_MINUS_DOUBLE:
-       case FILTER_OP_UNARY_NOT_DOUBLE:
        {
                /* Pop 1, push 1 */
                if (!vstack_ax(stack)) {
@@ -1024,9 +1056,13 @@ int exec_insn(struct bytecode_runtime *bytecode,
        /* get context ref */
        case FILTER_OP_GET_CONTEXT_REF:
        {
-               ERR("Unknown get context ref type\n");
-               ret = -EINVAL;
-               goto end;
+               if (vstack_push(stack)) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+               vstack_ax(stack)->type = REG_UNKNOWN;
+               next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
+               break;
        }
        case FILTER_OP_LOAD_FIELD_REF_STRING:
        case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
@@ -1171,7 +1207,7 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode)
                /*
                 * For each instruction, validate the current context
                 * (traversal of entire execution flow), and validate
-                * all  merge points targeting this instruction.
+                * all merge points targeting this instruction.
                 */
                ret = validate_instruction_all_contexts(bytecode, merge_points,
                                        &stack, start_pc, pc);
index d71485d166b30bc839b0b71dbd53307aae265def..ee94a4ccc2498d4c1272935e67dda7e1eadbe979 100644 (file)
@@ -228,20 +228,34 @@ int apply_context_reloc(struct lttng_event *event,
        struct load_op *op;
        struct lttng_ctx_field *ctx_field;
        int idx;
+       struct lttng_session *session = runtime->p.session;
 
        dbg_printf("Apply context reloc: %u %s\n", reloc_offset, context_name);
 
        /* Get context index */
-       idx = lttng_get_context_index(lttng_static_ctx, context_name);
-       if (idx < 0)
-               return -ENOENT;
-
+       idx = lttng_get_context_index(session->ctx, context_name);
+       if (idx < 0) {
+               if (lttng_context_is_app(context_name)) {
+                       int ret;
+
+                       ret = lttng_ust_add_app_context_to_ctx_rcu(context_name,
+                                       &session->ctx);
+                       if (ret)
+                               return ret;
+                       idx = lttng_get_context_index(session->ctx,
+                               context_name);
+                       if (idx < 0)
+                               return -ENOENT;
+               } else {
+                       return -ENOENT;
+               }
+       }
        /* Check if idx is too large for 16-bit offset */
        if (idx > FILTER_BYTECODE_MAX_LEN - 1)
                return -EINVAL;
 
        /* Get context return type */
-       ctx_field = &lttng_static_ctx->fields[idx];
+       ctx_field = &session->ctx->fields[idx];
        op = (struct load_op *) &runtime->data[reloc_offset];
        field_ref = (struct field_ref *) op->data;
        switch (ctx_field->event_field.type.atype) {
@@ -258,6 +272,9 @@ int apply_context_reloc(struct lttng_event *event,
        case atype_float:
                op->op = FILTER_OP_GET_CONTEXT_REF_DOUBLE;
                break;
+       case atype_dynamic:
+               op->op = FILTER_OP_GET_CONTEXT_REF;
+               break;
        default:
                return -EINVAL;
        }
@@ -339,6 +356,7 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event,
                goto alloc_error;
        }
        runtime->p.bc = filter_bytecode;
+       runtime->p.session = event->chan->session;
        runtime->len = filter_bytecode->bc.reloc_offset;
        /* copy original bytecode */
        memcpy(runtime->data, filter_bytecode->bc.data, runtime->len);
index fdc8ac67ed1ada4b72996240de380bf1e6bb3ebb..23ccff2318def4a882ee05fc6738a582e5949f0d 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <helper.h>
 #include <lttng/ust-events.h>
+#include <lttng/ust-context-provider.h>
 #include <stdint.h>
 #include <assert.h>
 #include <errno.h>
@@ -78,7 +79,7 @@ enum entry_type {
        REG_S64,
        REG_DOUBLE,
        REG_STRING,
-       REG_TYPE_UNKNOWN,
+       REG_UNKNOWN,
 };
 
 /* Validation stack */
@@ -137,6 +138,7 @@ int vstack_pop(struct vstack *stack)
 
 /* Execution stack */
 struct estack_entry {
+       enum entry_type type;   /* For dynamic typing. */
        union {
                int64_t v;
                double d;
@@ -154,9 +156,18 @@ struct estack {
        struct estack_entry e[FILTER_STACK_LEN];
 };
 
+/*
+ * Always use aliased type for ax/bx (top of stack).
+ * When ax/bx are S64, use aliased value.
+ */
 #define estack_ax_v    ax
 #define estack_bx_v    bx
+#define estack_ax_t    ax_t
+#define estack_bx_t    bx_t
 
+/*
+ * ax and bx registers can hold either integer, double or string.
+ */
 #define estack_ax(stack, top)                                  \
        ({                                                      \
                assert((top) > FILTER_STACK_EMPTY);             \
@@ -169,19 +180,26 @@ struct estack {
                &(stack)->e[(top) - 1];                         \
        })
 
-#define estack_push(stack, top, ax, bx)                                \
+/*
+ * Currently, only integers (REG_S64) can be pushed into the stack.
+ */
+#define estack_push(stack, top, ax, bx, ax_t, bx_t)            \
        do {                                                    \
                assert((top) < FILTER_STACK_LEN - 1);           \
                (stack)->e[(top) - 1].u.v = (bx);               \
+               (stack)->e[(top) - 1].type = (bx_t);            \
                (bx) = (ax);                                    \
+               (bx_t) = (ax_t);                                \
                ++(top);                                        \
        } while (0)
 
-#define estack_pop(stack, top, ax, bx)                         \
+#define estack_pop(stack, top, ax, bx, ax_t, bx_t)             \
        do {                                                    \
                assert((top) > FILTER_STACK_EMPTY);             \
                (ax) = (bx);                                    \
+               (ax_t) = (bx_t);                                \
                (bx) = (stack)->e[(top) - 2].u.v;               \
+               (bx_t) = (stack)->e[(top) - 2].type;            \
                (top)--;                                        \
        } while (0)
 
index 3f1e2656437a13b20d4fcbfd8f2b429622b83c78..d219b79c91dfb0ea45658865a97b0dded461ac20 100644 (file)
@@ -78,7 +78,7 @@ size_t ctx_get_size(size_t offset, struct lttng_ctx *ctx)
                return 0;
        offset += lib_ring_buffer_align(offset, ctx->largest_align);
        for (i = 0; i < ctx->nr_fields; i++)
-               offset += ctx->fields[i].get_size(offset);
+               offset += ctx->fields[i].get_size(&ctx->fields[i], offset);
        return offset - orig_offset;
 }
 
@@ -185,7 +185,7 @@ void lttng_write_event_header(const struct lttng_ust_lib_ring_buffer_config *con
                            uint32_t event_id)
 {
        struct lttng_channel *lttng_chan = channel_get_private(ctx->chan);
-       struct lttng_event *event = ctx->priv;
+       struct lttng_stack_ctx *lttng_ctx = ctx->priv2;
 
        if (caa_unlikely(ctx->rflags))
                goto slow_path;
@@ -220,8 +220,8 @@ void lttng_write_event_header(const struct lttng_ust_lib_ring_buffer_config *con
                WARN_ON_ONCE(1);
        }
 
-       ctx_record(ctx, lttng_chan, lttng_chan->ctx);
-       ctx_record(ctx, lttng_chan, event->ctx);
+       ctx_record(ctx, lttng_chan, lttng_ctx->chan_ctx);
+       ctx_record(ctx, lttng_chan, lttng_ctx->event_ctx);
        lib_ring_buffer_align_ctx(ctx, ctx->largest_align);
 
        return;
@@ -236,7 +236,7 @@ void lttng_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config
                                 uint32_t event_id)
 {
        struct lttng_channel *lttng_chan = channel_get_private(ctx->chan);
-       struct lttng_event *event = ctx->priv;
+       struct lttng_stack_ctx *lttng_ctx = ctx->priv2;
 
        switch (lttng_chan->header_type) {
        case 1: /* compact */
@@ -293,8 +293,8 @@ void lttng_write_event_header_slow(const struct lttng_ust_lib_ring_buffer_config
        default:
                WARN_ON_ONCE(1);
        }
-       ctx_record(ctx, lttng_chan, lttng_chan->ctx);
-       ctx_record(ctx, lttng_chan, event->ctx);
+       ctx_record(ctx, lttng_chan, lttng_ctx->chan_ctx);
+       ctx_record(ctx, lttng_chan, lttng_ctx->event_ctx);
        lib_ring_buffer_align_ctx(ctx, ctx->largest_align);
 }
 
index c619b5449dffafaa382927d63ff193656031bf02..1387aa82197f63e43dad5439368bec214fc2c1ae 100644 (file)
@@ -1520,7 +1520,6 @@ void __attribute__((constructor)) lttng_ust_init(void)
        lttng_ring_buffer_client_discard_init();
        lttng_ring_buffer_client_discard_rt_init();
        lttng_perf_counter_init();
-       lttng_context_init();
        /*
         * Invoke ust malloc wrapper init before starting other threads.
         */
@@ -1625,7 +1624,6 @@ void lttng_ust_cleanup(int exiting)
         */
        lttng_ust_abi_exit();
        lttng_ust_events_exit();
-       lttng_context_exit();
        lttng_perf_counter_exit();
        lttng_ring_buffer_client_discard_rt_exit();
        lttng_ring_buffer_client_discard_exit();
diff --git a/liblttng-ust/lttng-ust-dynamic-type.c b/liblttng-ust/lttng-ust-dynamic-type.c
new file mode 100644 (file)
index 0000000..c654f01
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * lttng-ust-dynamic-type.c
+ *
+ * UST dynamic type implementation.
+ *
+ * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <helper.h>
+#include <lttng/ust-dynamic-type.h>
+
+static const struct lttng_enum_entry dt_enum[_NR_LTTNG_UST_DYNAMIC_TYPES] = {
+       [LTTNG_UST_DYNAMIC_TYPE_NONE] = {
+               .start = 0,
+               .end = 0,
+               .string = "_none",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S8] = {
+               .start = 1,
+               .end = 1,
+               .string = "_int8",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S16] = {
+               .start = 2,
+               .end = 2,
+               .string = "_int16",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S32] = {
+               .start = 3,
+               .end = 3,
+               .string = "_int32",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S64] = {
+               .start = 4,
+               .end = 4,
+               .string = "_int64",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U8] = {
+               .start = 5,
+               .end = 5,
+               .string = "_uint8",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U16] = {
+               .start = 6,
+               .end = 6,
+               .string = "_uint16",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U32] = {
+               .start = 7,
+               .end = 7,
+               .string = "_uint32",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U64] = {
+               .start = 8,
+               .end = 8,
+               .string = "_uint64",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_FLOAT] = {
+               .start = 9,
+               .end = 9,
+               .string = "_float",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_DOUBLE] = {
+               .start = 10,
+               .end = 10,
+               .string = "_double",
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_STRING] = {
+               .start = 11,
+               .end = 11,
+               .string = "_string",
+       },
+};
+
+static const struct lttng_enum_desc dt_enum_desc = {
+       .name = "dynamic_type_enum",
+       .entries = dt_enum,
+       .nr_entries = LTTNG_ARRAY_SIZE(dt_enum),
+};
+
+const struct lttng_event_field dt_var_fields[_NR_LTTNG_UST_DYNAMIC_TYPES] = {
+       [LTTNG_UST_DYNAMIC_TYPE_NONE] = {
+               .name = "none",
+               .type = {
+                       .atype = atype_struct,
+                       .u._struct.nr_fields = 0,       /* empty struct. */
+               },
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S8] = {
+               .name = "int8",
+               .type = __type_integer(int8_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S16] = {
+               .name = "int16",
+               .type = __type_integer(int16_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S32] = {
+               .name = "int32",
+               .type = __type_integer(int32_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_S64] = {
+               .name = "int64",
+               .type = __type_integer(int64_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U8] = {
+               .name = "uint8",
+               .type = __type_integer(uint8_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U16] = {
+               .name = "uint16",
+               .type = __type_integer(uint16_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U32] = {
+               .name = "uint32",
+               .type = __type_integer(uint32_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_U64] = {
+               .name = "uint64",
+               .type = __type_integer(uint64_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_FLOAT] = {
+               .name = "float",
+               .type = __type_float(float),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_DOUBLE] = {
+               .name = "double",
+               .type = __type_float(double),
+               .nowrite = 0,
+       },
+       [LTTNG_UST_DYNAMIC_TYPE_STRING] = {
+               .name = "string",
+               .type = {
+                       .atype = atype_string,
+                       .u.basic.string.encoding = lttng_encode_UTF8,
+               },
+               .nowrite = 0,
+       },
+};
+
+static const struct lttng_event_field dt_enum_field = {
+       .name = NULL,
+       .type.atype = atype_enum,
+       .type.u.basic.enumeration.desc = &dt_enum_desc,
+       .type.u.basic.enumeration.container_type = {
+               .size = sizeof(char) * CHAR_BIT,
+               .alignment = lttng_alignof(char) * CHAR_BIT,
+               .signedness = lttng_is_signed_type(char),
+               .reverse_byte_order = 0,
+               .base = 10,
+               .encoding = lttng_encode_none,
+       },
+       .nowrite = 0,
+};
+
+const struct lttng_event_field *lttng_ust_dynamic_type_field(int64_t value)
+{
+       if (value >= _NR_LTTNG_UST_DYNAMIC_TYPES || value < 0)
+               return NULL;
+       return &dt_var_fields[value];
+}
+
+int lttng_ust_dynamic_type_choices(size_t *nr_choices, const struct lttng_event_field **choices)
+{
+       *nr_choices = _NR_LTTNG_UST_DYNAMIC_TYPES;
+       *choices = dt_var_fields;
+       return 0;
+}
+
+const struct lttng_event_field *lttng_ust_dynamic_type_tag_field(void)
+{
+       return &dt_enum_field;
+}
index be300c86e0443c531754fdd6e44358f79993b655..377acd676aeb7a46b4db32a6f793e24d831ca881 100644 (file)
@@ -1,5 +1,5 @@
 SUBDIRS = utils hello same_line_tracepoint snprintf benchmark ust-elf \
-               ctf-types
+               ctf-types test-app-ctx
 
 if CXX_WORKS
 SUBDIRS += hello.cxx
index 68c137ee304d043489c673713e1f2ab98d80cd58..058f7fae10abaa2c7c5a957c1bdc80fe40f8f8f1 100644 (file)
@@ -71,6 +71,8 @@ int init_int_handler(void)
        return 0;
 }
 
+void test_inc_count(void);
+
 int main(int argc, char **argv)
 {
        int i, netint;
diff --git a/tests/test-app-ctx/Makefile.am b/tests/test-app-ctx/Makefile.am
new file mode 100644 (file)
index 0000000..324c2cd
--- /dev/null
@@ -0,0 +1,13 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -Wsystem-headers
+
+noinst_PROGRAMS = hello
+hello_SOURCES = hello.c tp.c ust_tests_hello.h
+hello_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la
+hello_CFLAGS = -Werror=old-style-definition
+
+if LTTNG_UST_BUILD_WITH_LIBDL
+hello_LDADD += -ldl
+endif
+if LTTNG_UST_BUILD_WITH_LIBC_DL
+hello_LDADD += -lc
+endif
diff --git a/tests/test-app-ctx/hello.c b/tests/test-app-ctx/hello.c
new file mode 100644 (file)
index 0000000..197df21
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2009  Pierre-Marc Fournier
+ * Copyright (C) 2011  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1 of
+ * the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+/*
+ * Work-around inet.h missing struct mmsghdr forward declaration, with
+ * triggers a warning when system files warnings are enabled.
+ */
+struct mmsghdr;
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define TRACEPOINT_DEFINE
+#include "ust_tests_hello.h"
+
+/* Internal header. */
+#include <lttng/ust-events.h>
+#include <lttng/ringbuffer-config.h>
+#include <lttng/ust-context-provider.h>
+
+static __thread unsigned int test_count;
+
+void test_inc_count(void)
+{
+       test_count++;
+}
+
+static
+size_t test_get_size(struct lttng_ctx_field *field, size_t offset)
+{
+       int sel = test_count % _NR_LTTNG_UST_DYNAMIC_TYPES;
+       size_t size = 0;
+
+       size += lib_ring_buffer_align(offset, lttng_alignof(char));
+       size += sizeof(char);           /* tag */
+       switch (sel) {
+       case LTTNG_UST_DYNAMIC_TYPE_NONE:
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S8:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int8_t));
+               size += sizeof(int8_t);         /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S16:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int16_t));
+               size += sizeof(int16_t);        /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S32:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int32_t));
+               size += sizeof(int32_t);        /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S64:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int64_t));
+               size += sizeof(int64_t);        /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U8:
+               size += lib_ring_buffer_align(offset, lttng_alignof(uint8_t));
+               size += sizeof(uint8_t);                /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U16:
+               size += lib_ring_buffer_align(offset, lttng_alignof(uint16_t));
+               size += sizeof(uint16_t);       /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U32:
+               size += lib_ring_buffer_align(offset, lttng_alignof(uint32_t));
+               size += sizeof(uint32_t);       /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U64:
+               size += lib_ring_buffer_align(offset, lttng_alignof(uint64_t));
+               size += sizeof(uint64_t);       /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_FLOAT:
+               size += lib_ring_buffer_align(offset, lttng_alignof(float));
+               size += sizeof(float);          /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_DOUBLE:
+               size += lib_ring_buffer_align(offset, lttng_alignof(double));
+               size += sizeof(double);         /* variant */
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_STRING:
+               size += strlen("teststr") + 1;
+               break;
+       default:
+               abort();
+       }
+
+       return size;
+}
+
+static
+void test_record(struct lttng_ctx_field *field,
+                struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                struct lttng_channel *chan)
+{
+       int sel = test_count % _NR_LTTNG_UST_DYNAMIC_TYPES;
+       char sel_char = (char) sel;
+
+       lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+       chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+       switch (sel) {
+       case LTTNG_UST_DYNAMIC_TYPE_NONE:
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S8:
+       {
+               int8_t v = -8;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_S16:
+       {
+               int16_t v = -16;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_S32:
+       {
+               int32_t v = -32;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_S64:
+       {
+               int64_t v = -64;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_U8:
+       {
+               uint8_t v = 8;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_U16:
+       {
+               uint16_t v = 16;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_U32:
+       {
+               uint32_t v = 32;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_U64:
+       {
+               uint64_t v = 64;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_FLOAT:
+       {
+               float f = 22322.0;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(f));
+               chan->ops->event_write(ctx, &f, sizeof(f));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_DOUBLE:
+       {
+               double d = 2.0;
+
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(d));
+               chan->ops->event_write(ctx, &d, sizeof(d));
+               break;
+       }
+       case LTTNG_UST_DYNAMIC_TYPE_STRING:
+       {
+               const char *str = "teststr";
+               chan->ops->event_write(ctx, str, strlen(str) + 1);
+               break;
+       }
+       default:
+               abort();
+       }
+}
+
+static
+void test_get_value(struct lttng_ctx_field *field,
+               struct lttng_ctx_value *value)
+{
+       int sel = test_count % _NR_LTTNG_UST_DYNAMIC_TYPES;
+
+       value->sel = sel;
+       switch (sel) {
+       case LTTNG_UST_DYNAMIC_TYPE_NONE:
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S8:
+               value->u.s64 = -8;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S16:
+               value->u.s64 = -16;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S32:
+               value->u.s64 = -32;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_S64:
+               value->u.s64 = -64;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U8:
+               value->u.s64 = 8;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U16:
+               value->u.s64 = 16;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U32:
+               value->u.s64 = 32;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_U64:
+               value->u.s64 = 64;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_FLOAT:
+               value->u.d = 22322.0;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_DOUBLE:
+               value->u.d = 2.0;
+               break;
+       case LTTNG_UST_DYNAMIC_TYPE_STRING:
+               value->u.str = "teststr";
+               break;
+       default:
+               abort();
+       }
+}
+
+struct lttng_ust_context_provider myprovider = {
+       .name = "$app.myprovider",
+       .get_size = test_get_size,
+       .record = test_record,
+       .get_value = test_get_value,
+};
+
+void inthandler(int sig)
+{
+       printf("in SIGUSR1 handler\n");
+       tracepoint(ust_tests_hello, tptest_sighandler);
+}
+
+int init_int_handler(void)
+{
+       int result;
+       struct sigaction act;
+
+       memset(&act, 0, sizeof(act));
+       result = sigemptyset(&act.sa_mask);
+       if (result == -1) {
+               perror("sigemptyset");
+               return -1;
+       }
+
+       act.sa_handler = inthandler;
+       act.sa_flags = SA_RESTART;
+
+       /* Only defer ourselves. Also, try to restart interrupted
+        * syscalls to disturb the traced program as little as possible.
+        */
+       result = sigaction(SIGUSR1, &act, NULL);
+       if (result == -1) {
+               perror("sigaction");
+               return -1;
+       }
+
+       return 0;
+}
+
+void test_inc_count(void);
+
+int main(int argc, char **argv)
+{
+       int i, netint;
+       long values[] = { 1, 2, 3 };
+       char text[10] = "test";
+       double dbl = 2.0;
+       float flt = 2222.0;
+       int delay = 0;
+       bool mybool = 123;      /* should print "1" */
+
+       init_int_handler();
+
+       if (argc == 2)
+               delay = atoi(argv[1]);
+
+       if (lttng_ust_context_provider_register(&myprovider))
+               abort();
+
+       fprintf(stderr, "Hello, World!\n");
+
+       sleep(delay);
+
+       fprintf(stderr, "Tracing... ");
+       for (i = 0; i < 1000000; i++) {
+               netint = htonl(i);
+               tracepoint(ust_tests_hello, tptest, i, netint, values,
+                          text, strlen(text), dbl, flt, mybool);
+               test_inc_count();
+               //usleep(100000);
+       }
+       lttng_ust_context_provider_unregister(&myprovider);
+       fprintf(stderr, " done.\n");
+       return 0;
+}
diff --git a/tests/test-app-ctx/tp.c b/tests/test-app-ctx/tp.c
new file mode 100644 (file)
index 0000000..4790965
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * tp.c
+ *
+ * Copyright (c) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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.
+ */
+
+#define TRACEPOINT_CREATE_PROBES
+#include "ust_tests_hello.h"
diff --git a/tests/test-app-ctx/ust_tests_hello.h b/tests/test-app-ctx/ust_tests_hello.h
new file mode 100644 (file)
index 0000000..e518b0d
--- /dev/null
@@ -0,0 +1,68 @@
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER ust_tests_hello
+
+#if !defined(_TRACEPOINT_UST_TESTS_HELLO_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define _TRACEPOINT_UST_TESTS_HELLO_H
+
+/*
+ * Copyright (C) 2011  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <lttng/tracepoint.h>
+#include <stdbool.h>
+
+TRACEPOINT_EVENT(ust_tests_hello, tptest,
+       TP_ARGS(int, anint, int, netint, long *, values,
+               char *, text, size_t, textlen,
+               double, doublearg, float, floatarg,
+               bool, boolarg),
+       TP_FIELDS(
+               ctf_integer(int, intfield, anint)
+               ctf_integer_hex(int, intfield2, anint)
+               ctf_integer(long, longfield, anint)
+               ctf_integer_network(int, netintfield, netint)
+               ctf_integer_network_hex(int, netintfieldhex, netint)
+               ctf_array(long, arrfield1, values, 3)
+               ctf_array_text(char, arrfield2, text, 10)
+               ctf_sequence(char, seqfield1, text,
+                            size_t, textlen)
+               ctf_sequence_text(char, seqfield2, text,
+                            size_t, textlen)
+               ctf_string(stringfield, text)
+               ctf_float(float, floatfield, floatarg)
+               ctf_float(double, doublefield, doublearg)
+               ctf_integer(bool, boolfield, boolarg)
+               ctf_integer_nowrite(int, filterfield, anint)
+       )
+)
+
+TRACEPOINT_EVENT(ust_tests_hello, tptest_sighandler,
+       TP_ARGS(),
+       TP_FIELDS()
+)
+
+#endif /* _TRACEPOINT_UST_TESTS_HELLO_H */
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./ust_tests_hello.h"
+
+/* This part must be outside ifdef protection */
+#include <lttng/tracepoint-event.h>
diff --git a/tests/ust-variant/Makefile.am b/tests/ust-variant/Makefile.am
new file mode 100644 (file)
index 0000000..3c3d61d
--- /dev/null
@@ -0,0 +1,13 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -Wsystem-headers
+
+noinst_PROGRAMS = ust-variant
+ust_variant_SOURCES = ust-variant.c
+ust_variant_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la
+ust_variant_CFLAGS = -Werror=old-style-definition
+
+if LTTNG_UST_BUILD_WITH_LIBDL
+ust_variant_LDADD += -ldl
+endif
+if LTTNG_UST_BUILD_WITH_LIBC_DL
+ust_variant_LDADD += -lc
+endif
diff --git a/tests/ust-variant/ust-variant.c b/tests/ust-variant/ust-variant.c
new file mode 100644 (file)
index 0000000..3d97c1a
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1 of
+ * the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+/* Internal UST API: ust-variant.h */
+#include <lttng/ust-variant.h>
+#include <lttng/ust-events.h>
+#include <helper.h>
+
+#define NR_ENTRIES     5
+
+static const struct lttng_enum_entry myentries[NR_ENTRIES] = {
+       [0] = {
+               .start = 0,
+               .end = 0,
+               .string = "_mystring",
+       },
+       [1] = {
+               .start = 1,
+               .end = 1,
+               .string = "_myint32",
+       },
+       [2] = {
+               .start = 2,
+               .end = 2,
+               .string = "_myuint16",
+       },
+       [3] = {
+               .start = 3,
+               .end = 3,
+               .string = "_mychar",
+       },
+       [4] = {
+               .start = 4,
+               .end = 4,
+               .string = "_mylonglong",
+       },
+};
+
+static const struct lttng_enum_desc myenum_desc = {
+       .name = "myenum",
+       .entries = myentries,
+       .nr_entries = LTTNG_ARRAY_SIZE(myentries),
+};
+
+const struct lttng_event_field myvarfields[NR_ENTRIES] = {
+       [0] = {
+               .name = "mystring",
+               .type = {
+                       .atype = atype_string,
+                       .u.basic.string.encoding = lttng_encode_UTF8,
+               },
+               .nowrite = 0,
+       },
+       [1] = {
+               .name = "myint32",
+               .type = __type_integer(int32_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [2] = {
+               .name = "myuint16",
+               .type = __type_integer(uint16_t, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [3] = {
+               .name = "mychar",
+               .type = __type_integer(char, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+       [4] = {
+               .name = "mylonglong",
+               .type = __type_integer(long long, BYTE_ORDER, 10, none),
+               .nowrite = 0,
+       },
+};
+
+static const struct lttng_event_field *get_field(const struct lttng_ust_type_variant *variant,
+               int64_t value)
+{
+       if (value >= NR_ENTRIES || value < 0)
+               return NULL;
+       return &myvarfields[value];
+}
+
+static int get_choices(const struct lttng_ust_type_variant *variant,
+               size_t *nr_choices, const struct lttng_event_field **choices)
+{
+       *nr_choices = NR_ENTRIES;
+       *choices = myvarfields;
+       return 0;
+}
+
+static const struct lttng_event_field myfields[];
+
+static const struct lttng_ust_type_variant myvariant = {
+       .tag = &myfields[0],
+       .get_field = get_field,
+       .get_choices = get_choices,
+       .free_priv = NULL,
+       .priv = NULL,
+};
+
+/* dummy event */
+
+static void __event_probe__myprobe___myevent(void * __tp_data)
+{
+}
+
+static const struct lttng_event_field myfields[] = {
+       [0] = {
+               .name = "mytag",
+               .type.atype = atype_enum,
+               .type.u.basic.enumeration.desc = &myenum_desc,
+               .type.u.basic.enumeration.container_type = {
+                       .size = sizeof(char) * CHAR_BIT,
+                       .alignment = lttng_alignof(char) * CHAR_BIT,
+                       .signedness = lttng_is_signed_type(char),
+                       .reverse_byte_order = 0,
+                       .base = 10,
+                       .encoding = lttng_encode_none,
+               },
+               .nowrite = 0,
+       },
+       [1] = {
+               .name = "myfield",
+               .type = {
+                       .atype = atype_variant,
+                       .u.variant = &myvariant,
+               },
+               .nowrite = 0,
+       },
+};
+
+static const struct lttng_event_desc myevent_desc = {
+       .name = "myprobe:myevent",
+       .probe_callback = (void (*)(void)) &__event_probe__myprobe___myevent,
+       .ctx = NULL,
+       .fields = myfields,
+       .nr_fields = LTTNG_ARRAY_SIZE(myfields),
+       .loglevel = NULL,
+       .signature = "mysig",
+       .u = {
+               .ext = {
+                       .model_emf_uri = NULL,
+               },
+       },
+};
+
+static const struct lttng_event_desc *event_desc_array[] = {
+       [0] = &myevent_desc,
+};
+
+/* Dummy probe. */
+
+static struct lttng_probe_desc __probe_desc___myprobe = {
+       .provider = "myprobe",
+       .event_desc = event_desc_array,
+       .nr_events = LTTNG_ARRAY_SIZE(event_desc_array),
+       .head = { NULL, NULL },
+       .lazy_init_head = { NULL, NULL },
+       .lazy = 0,
+       .major = LTTNG_UST_PROVIDER_MAJOR,
+       .minor = LTTNG_UST_PROVIDER_MINOR,
+};
+
+int main(int argc, char **argv)
+{
+       int ret;
+
+       ret = lttng_probe_register(&__probe_desc___myprobe);
+       if (ret)
+               abort();
+       sleep(5);
+       lttng_probe_unregister(&__probe_desc___myprobe);
+
+       return 0;
+}
This page took 0.103947 seconds and 5 git commands to generate.