Implement capturing payload on event notifiers
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Mon, 6 Apr 2020 18:59:08 +0000 (14:59 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 26 Nov 2020 18:40:02 +0000 (13:40 -0500)
This commit allows the user to request a subset of payload fields of the
tracepoint to be captured when a event notifier is fired and sent back
the session daemon as part of the notification.

Captures are really similar to filter in the way they work. Like with
filters, the sessiond attaches to a event notifier one bytecode program
per field it wants to capture using the following function:

  int ustctl_set_capture(int sock, struct lttng_ust_capture_bytecode *bytecode,
         struct lttng_ust_object_data *obj_data);

The capture bytecode program is then validated and specialized for its
target tracepoint just like filter bytecode programs.

The major difference between filters and captures is with what they
return. Filters can only return _RECORD or _DISCARD for match and
no-match respectively. Captures also need to return captured values. For
this reason, we added an output parameter to the capture interpreter
function that value can be extracted.

Here is the signature of the capture interpreter function:
  uint64_t lttng_bytecode_capture_interpret(void *capture_data,
         const char *capture_stack_data,
         void *output)

When comes the time to send the notification, every capture bytecode
program is executed in turns and its output value is recorded to the
capture buffer to be sent back to the sessiond.

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Ia3023a4f5c0aec014b37b72f92d1a924c7eff6a2

14 files changed:
include/lttng/ust-abi.h
include/lttng/ust-ctl.h
include/lttng/ust-events.h
include/lttng/ust-tracepoint-event.h
include/ust-comm.h
liblttng-ust-ctl/ustctl.c
liblttng-ust/event-notifier-notification.c
liblttng-ust/lttng-bytecode-interpreter.c
liblttng-ust/lttng-bytecode.c
liblttng-ust/lttng-bytecode.h
liblttng-ust/lttng-events.c
liblttng-ust/lttng-ust-abi.c
liblttng-ust/lttng-ust-comm.c
liblttng-ust/ust-events-internal.h

index 302e6a36b80cb441cca42d7a3d6a297f3fd099ea..1c80c14408937a3f14e89c1f1125efb4c2b4edd1 100644 (file)
@@ -129,6 +129,7 @@ struct lttng_ust_event_notifier {
 #define LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
 struct lttng_ust_event_notifier_notification {
        uint64_t token;
+       uint16_t capture_buf_size;
        char padding[LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING];
 } LTTNG_PACKED;
 
@@ -282,6 +283,16 @@ struct lttng_ust_filter_bytecode {
        char data[0];
 } LTTNG_PACKED;
 
+#define CAPTURE_BYTECODE_MAX_LEN       65536
+#define LTTNG_UST_CAPTURE_PADDING      32
+struct lttng_ust_capture_bytecode {
+       uint32_t len;
+       uint32_t reloc_offset;
+       uint64_t seqnum;
+       char padding[LTTNG_UST_CAPTURE_PADDING];
+       char data[0];
+} LTTNG_PACKED;
+
 #define LTTNG_UST_EXCLUSION_PADDING    32
 struct lttng_ust_event_exclusion {
        uint32_t count;
@@ -341,6 +352,7 @@ struct lttng_ust_event_exclusion {
 /* Event notifier group commands */
 #define LTTNG_UST_EVENT_NOTIFIER_CREATE                \
        _UST_CMDW(0xB0, struct lttng_ust_event_notifier)
+#define LTTNG_UST_CAPTURE                      _UST_CMD(0xB1)
 
 #define LTTNG_UST_ROOT_HANDLE  0
 
index a4d54c42bbdec1506133c53f7f92cc315d5d137d..35b7334220dc77f52a99bbade9e4d192dcfba8b5 100644 (file)
@@ -93,6 +93,8 @@ int ustctl_add_context(int sock, struct lttng_ust_context_attr *ctx,
                struct lttng_ust_object_data **context_data);
 int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode,
                struct lttng_ust_object_data *obj_data);
+int ustctl_set_capture(int sock, struct lttng_ust_capture_bytecode *bytecode,
+               struct lttng_ust_object_data *obj_data);
 int ustctl_set_exclusion(int sock, struct lttng_ust_event_exclusion *exclusion,
                struct lttng_ust_object_data *obj_data);
 
index 5bd158386cdfeba881597d5b1bc3c0b17076ee94..44b8d4c4878819d57b2a13b7130e9c28862540d7 100644 (file)
@@ -435,6 +435,8 @@ enum lttng_bytecode_interpreter_ret {
        /* Other bits are kept for future use. */
 };
 
+struct lttng_interpreter_output;
+
 /*
  * This structure is used in the probes. More specifically, the `filter` and
  * `node` fields are explicity used in the probes. When modifying this
@@ -447,6 +449,9 @@ struct lttng_bytecode_runtime {
        union {
                uint64_t (*filter)(void *interpreter_data,
                                const char *interpreter_stack_data);
+               uint64_t (*capture)(void *interpreter_data,
+                               const char *interpreter_stack_data,
+                               struct lttng_interpreter_output *interpreter_output);
        } interpreter_funcs;
        int link_failed;
        struct cds_list_head node;      /* list of bytecode runtime in event */
@@ -507,7 +512,9 @@ struct lttng_event_notifier {
        uint64_t user_token;
        int enabled;
        int registered;                 /* has reg'd tracepoint probe */
+       size_t num_captures;            /* Needed to allocate the msgpack array. */
        struct cds_list_head filter_bytecode_runtime_head;
+       struct cds_list_head capture_bytecode_runtime_head;
        int has_enablers_without_bytecode;
        struct cds_list_head enablers_ref_head;
        const struct lttng_event_desc *desc;
@@ -695,7 +702,8 @@ int lttng_session_statedump(struct lttng_session *session);
 void lttng_session_destroy(struct lttng_session *session);
 
 void lttng_event_notifier_notification_send(
-               struct lttng_event_notifier *event_notifier);
+               struct lttng_event_notifier *event_notifier,
+               const char *stack_data);
 
 struct lttng_channel *lttng_channel_create(struct lttng_session *session,
                                       const char *transport_name,
index 1f8be1a99efd4c5eeb80fd4d6db775dfbd835b11..0a397e50c6871e18d4d30bfbe7709343422ca9ad 100644 (file)
@@ -665,7 +665,7 @@ size_t __event_get_size__##_provider##___##_name(size_t *__dynamic_len, _TP_ARGS
 #undef TRACEPOINT_EVENT_CLASS
 #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields)             \
 static inline                                                                \
-void __event_prepare_filter_stack__##_provider##___##_name(char *__stack_data,\
+void __event_prepare_interpreter_stack__##_provider##___##_name(char *__stack_data,\
                                                 _TP_ARGS_DATA_PROTO(_args))  \
 {                                                                            \
        _fields                                                               \
@@ -875,7 +875,7 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))           \
                struct lttng_bytecode_runtime *__filter_bc_runtime;                   \
                int __filter_record = __event->has_enablers_without_bytecode; \
                                                                              \
-               __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
+               __event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
                        _TP_ARGS_DATA_VAR(_args));                            \
                tp_list_for_each_entry_rcu(__filter_bc_runtime, &__event->filter_bytecode_runtime_head, node) { \
                        if (caa_unlikely(__filter_bc_runtime->interpreter_funcs.filter(__filter_bc_runtime,     \
@@ -947,7 +947,7 @@ void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))
        const size_t __num_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1;\
        union {                                                               \
                size_t __dynamic_len[__num_fields];                           \
-               char __filter_stack_data[2 * sizeof(unsigned long) * __num_fields]; \
+               char __interpreter_stack_data[2 * sizeof(unsigned long) * __num_fields]; \
        } __stackvar;                                                         \
        if (caa_unlikely(!CMM_ACCESS_ONCE(__event_notifier->enabled)))        \
                return;                                                       \
@@ -957,18 +957,22 @@ void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))
                struct lttng_bytecode_runtime *__filter_bc_runtime;                    \
                int __filter_record = __event_notifier->has_enablers_without_bytecode; \
                                                                              \
-               __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
+               __event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__interpreter_stack_data, \
                        _TP_ARGS_DATA_VAR(_args));                            \
                tp_list_for_each_entry_rcu(__filter_bc_runtime, &__event_notifier->filter_bytecode_runtime_head, node) { \
                        if (caa_unlikely(__filter_bc_runtime->interpreter_funcs.filter(__filter_bc_runtime,       \
-                                       __stackvar.__filter_stack_data) & LTTNG_INTERPRETER_RECORD_FLAG)) \
+                                       __stackvar.__interpreter_stack_data) & LTTNG_INTERPRETER_RECORD_FLAG)) \
                                __filter_record = 1;                          \
                }                                                             \
                if (caa_likely(!__filter_record))                             \
                        return;                                               \
        }                                                                     \
+       if (caa_unlikely(!cds_list_empty(&__event_notifier->capture_bytecode_runtime_head))) \
+               __event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__interpreter_stack_data, \
+                       _TP_ARGS_DATA_VAR(_args));                            \
                                                                              \
-       lttng_event_notifier_notification_send(__event_notifier);             \
+       lttng_event_notifier_notification_send(__event_notifier,              \
+                       __stackvar.__interpreter_stack_data);                 \
 }
 
 #include TRACEPOINT_INCLUDE
index c9c8ca419f6a4aaffd4cf30d2834820b6b55c58a..fbaef54425142c4bab07e983e7a8a7fb3c13a3e2 100644 (file)
@@ -103,6 +103,11 @@ struct ustcomm_ust_msg {
                struct {
                        uint32_t count; /* how many names follow */
                } LTTNG_PACKED exclusion;
+               struct {
+                       uint32_t data_size;     /* following capture data */
+                       uint32_t reloc_offset;
+                       uint64_t seqnum;
+               } LTTNG_PACKED capture;
                char padding[USTCOMM_MSG_PADDING2];
        } u;
 } LTTNG_PACKED;
index 744f66ba6dc9824c00329540d41c88294644bb2c..b2fa8258163961c799d868c4f02f798c3e262558 100644 (file)
@@ -333,6 +333,37 @@ int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode,
        return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
 }
 
+int ustctl_set_capture(int sock, struct lttng_ust_capture_bytecode *bytecode,
+               struct lttng_ust_object_data *obj_data)
+{
+       struct ustcomm_ust_msg lum;
+       struct ustcomm_ust_reply lur;
+       int ret;
+
+       if (!obj_data)
+               return -EINVAL;
+
+       memset(&lum, 0, sizeof(lum));
+       lum.handle = obj_data->handle;
+       lum.cmd = LTTNG_UST_CAPTURE;
+       lum.u.capture.data_size = bytecode->len;
+       lum.u.capture.reloc_offset = bytecode->reloc_offset;
+       lum.u.capture.seqnum = bytecode->seqnum;
+
+       ret = ustcomm_send_app_msg(sock, &lum);
+       if (ret)
+               return ret;
+       /* send var len bytecode */
+       ret = ustcomm_send_unix_sock(sock, bytecode->data,
+                               bytecode->len);
+       if (ret < 0) {
+               return ret;
+       }
+       if (ret != bytecode->len)
+               return -EINVAL;
+       return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
+}
+
 int ustctl_set_exclusion(int sock, struct lttng_ust_event_exclusion *exclusion,
                struct lttng_ust_object_data *obj_data)
 {
index 844438f2378a329763a90d5f49e431062d89253b..6fce4357fe85fe5d1511495b675449b5e10797a6 100644 (file)
 #include "lttng-bytecode.h"
 #include "share.h"
 
-static
-void capture_enum(struct lttng_msgpack_writer *writer,
-               struct lttng_interpreter_output *output) __attribute__ ((unused));
+/*
+ * We want this write to be atomic AND non-blocking, meaning that we
+ * want to write either everything OR nothing.
+ * According to `pipe(7)`, writes that are less than `PIPE_BUF` bytes must be
+ * atomic, so we bound the capture buffer size to the `PIPE_BUF` minus the size
+ * of the notification struct we are sending alongside the capture buffer.
+ */
+#define CAPTURE_BUFFER_SIZE \
+       (PIPE_BUF - sizeof(struct lttng_ust_event_notifier_notification) - 1)
+
+struct lttng_event_notifier_notification {
+       int notification_fd;
+       uint64_t event_notifier_token;
+       uint8_t capture_buf[CAPTURE_BUFFER_SIZE];
+       struct lttng_msgpack_writer writer;
+       bool has_captures;
+};
+
 static
 void capture_enum(struct lttng_msgpack_writer *writer,
                struct lttng_interpreter_output *output)
@@ -155,9 +170,6 @@ uint64_t capture_sequence_element_unsigned(uint8_t *ptr,
        return value;
 }
 
-static
-void capture_sequence(struct lttng_msgpack_writer *writer,
-               struct lttng_interpreter_output *output) __attribute__ ((unused));
 static
 void capture_sequence(struct lttng_msgpack_writer *writer,
                struct lttng_interpreter_output *output)
@@ -210,27 +222,111 @@ void capture_sequence(struct lttng_msgpack_writer *writer,
        lttng_msgpack_end_array(writer);
 }
 
-void lttng_event_notifier_notification_send(
+static
+void notification_init(struct lttng_event_notifier_notification *notif,
                struct lttng_event_notifier *event_notifier)
 {
+       struct lttng_msgpack_writer *writer = &notif->writer;
+
+       notif->event_notifier_token = event_notifier->user_token;
+       notif->notification_fd = event_notifier->group->notification_fd;
+       notif->has_captures = false;
+
+       if (event_notifier->num_captures > 0) {
+               lttng_msgpack_writer_init(writer, notif->capture_buf,
+                               CAPTURE_BUFFER_SIZE);
+
+               lttng_msgpack_begin_array(writer, event_notifier->num_captures);
+               notif->has_captures = true;
+       }
+}
+
+static
+void notification_append_capture(
+               struct lttng_event_notifier_notification *notif,
+               struct lttng_interpreter_output *output)
+{
+       struct lttng_msgpack_writer *writer = &notif->writer;
+
+       switch (output->type) {
+       case LTTNG_INTERPRETER_TYPE_S64:
+               lttng_msgpack_write_signed_integer(writer, output->u.s);
+               break;
+       case LTTNG_INTERPRETER_TYPE_U64:
+               lttng_msgpack_write_unsigned_integer(writer, output->u.u);
+               break;
+       case LTTNG_INTERPRETER_TYPE_DOUBLE:
+               lttng_msgpack_write_double(writer, output->u.d);
+               break;
+       case LTTNG_INTERPRETER_TYPE_STRING:
+               lttng_msgpack_write_str(writer, output->u.str.str);
+               break;
+       case LTTNG_INTERPRETER_TYPE_SEQUENCE:
+               capture_sequence(writer, output);
+               break;
+       case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
+       case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
+               capture_enum(writer, output);
+               break;
+       default:
+               abort();
+       }
+}
+
+static
+void notification_append_empty_capture(
+               struct lttng_event_notifier_notification *notif)
+{
+       lttng_msgpack_write_nil(&notif->writer);
+}
+
+static
+void notification_send(struct lttng_event_notifier_notification *notif)
+{
+       ssize_t ret;
+       size_t content_len;
+       int iovec_count = 1;
+       struct lttng_ust_event_notifier_notification ust_notif;
+       struct iovec iov[2];
+
+       assert(notif);
+
+       ust_notif.token = notif->event_notifier_token;
+
        /*
-        * We want this write to be atomic AND non-blocking, meaning that we
-        * want to write either everything OR nothing.
-        * According to `pipe(7)`, writes that are smaller that the `PIPE_BUF`
-        * value must be atomic, so we assert that the message we send is less
-        * than PIPE_BUF.
+        * Prepare sending the notification from multiple buffers using an
+        * array of `struct iovec`. The first buffer of the vector is
+        * notification structure itself and is always present.
         */
-       struct lttng_ust_event_notifier_notification notif;
-       ssize_t ret;
+       iov[0].iov_base = &ust_notif;
+       iov[0].iov_len = sizeof(ust_notif);
+
+       if (notif->has_captures) {
+               /*
+                * If captures were requested, the second buffer of the array
+                * is the capture buffer.
+                */
+               assert(notif->writer.buffer);
+               content_len = notif->writer.write_pos - notif->writer.buffer;
 
-       assert(event_notifier);
-       assert(event_notifier->group);
-       assert(sizeof(notif) <= PIPE_BUF);
+               assert(content_len > 0 && content_len <= CAPTURE_BUFFER_SIZE);
 
-       notif.token = event_notifier->user_token;
+               iov[1].iov_base = notif->capture_buf;
+               iov[1].iov_len = content_len;
+
+               iovec_count++;
+       } else {
+               content_len = 0;
+       }
+
+       /*
+        * Update the capture buffer size so that receiver of the buffer will
+        * know how much to expect.
+        */
+       ust_notif.capture_buf_size = content_len;
 
-       ret = patient_write(event_notifier->group->notification_fd, &notif,
-               sizeof(notif));
+       /* Send all the buffers. */
+       ret = patient_writev(notif->notification_fd, iov, iovec_count);
        if (ret == -1) {
                if (errno == EAGAIN) {
                        DBG("Cannot send event notifier notification without blocking: %s",
@@ -242,3 +338,42 @@ void lttng_event_notifier_notification_send(
                }
        }
 }
+
+void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier,
+               const char *stack_data)
+{
+       /*
+        * This function is called from the probe, we must do dynamic
+        * allocation in this context.
+        */
+       struct lttng_event_notifier_notification notif = {0};
+
+       notification_init(&notif, event_notifier);
+
+       if (caa_unlikely(!cds_list_empty(&event_notifier->capture_bytecode_runtime_head))) {
+               struct lttng_bytecode_runtime *capture_bc_runtime;
+
+               /*
+                * Iterate over all the capture bytecodes. If the interpreter
+                * functions returns successfully, append the value of the
+                * `output` parameter to the capture buffer. If the interpreter
+                * fails, append an empty capture to the buffer.
+                */
+               cds_list_for_each_entry(capture_bc_runtime,
+                               &event_notifier->capture_bytecode_runtime_head, node) {
+                       struct lttng_interpreter_output output;
+
+                       if (capture_bc_runtime->interpreter_funcs.capture(capture_bc_runtime,
+                                       stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG)
+                               notification_append_capture(&notif, &output);
+                       else
+                               notification_append_empty_capture(&notif);
+               }
+       }
+
+       /*
+        * Send the notification (including the capture buffer) to the
+        * sessiond.
+        */
+       notification_send(&notif);
+}
index ea5eca191d988b45b0d5d5ae1ebf90236130b8ff..bba3cac8dcb8991f35238207eb3ba16701eb840e 100644 (file)
@@ -172,6 +172,13 @@ uint64_t lttng_bytecode_filter_interpret_false(void *filter_data,
        return LTTNG_INTERPRETER_DISCARD;
 }
 
+uint64_t lttng_bytecode_capture_interpret_false(void *capture_data,
+               const char *capture_stack_data,
+               struct lttng_interpreter_output *output)
+{
+       return LTTNG_INTERPRETER_DISCARD;
+}
+
 #ifdef INTERPRETER_USE_SWITCH
 
 /*
@@ -751,9 +758,12 @@ again:
 }
 
 /*
- * Return 0 (discard), or raise the 0x1 flag (log event).
- * Currently, other flags are kept for future extensions and have no
- * effect.
+ * For `output` equal to NULL:
+ *  Return 0 (discard), or raise the 0x1 flag (log event).
+ *  Currently, other flags are kept for future extensions and have no
+ *  effect.
+ * For `output` not equal to NULL:
+ *  Return 0 on success, negative error value on error.
  */
 static
 uint64_t bytecode_interpret(void *interpreter_data,
@@ -2544,6 +2554,14 @@ uint64_t lttng_bytecode_filter_interpret(void *filter_data,
        return bytecode_interpret(filter_data, filter_stack_data, NULL);
 }
 
+uint64_t lttng_bytecode_capture_interpret(void *capture_data,
+               const char *capture_stack_data,
+               struct lttng_interpreter_output *output)
+{
+       return bytecode_interpret(capture_data, capture_stack_data,
+                       (struct lttng_interpreter_output *) output);
+}
+
 #undef START_OP
 #undef OP
 #undef PO
index a6527ff191e1a34f706933523a1248c48d4c2321..30d3cbd105d2eb029f83482ab1f013ade312c496 100644 (file)
@@ -483,6 +483,9 @@ int link_bytecode(const struct lttng_event_desc *event_desc,
        case LTTNG_UST_BYTECODE_NODE_TYPE_FILTER:
                runtime->p.interpreter_funcs.filter = lttng_bytecode_filter_interpret;
                break;
+       case LTTNG_UST_BYTECODE_NODE_TYPE_CAPTURE:
+               runtime->p.interpreter_funcs.capture = lttng_bytecode_capture_interpret;
+               break;
        default:
                abort();
        }
@@ -497,6 +500,9 @@ link_error:
        case LTTNG_UST_BYTECODE_NODE_TYPE_FILTER:
                runtime->p.interpreter_funcs.filter = lttng_bytecode_filter_interpret_false;
                break;
+       case LTTNG_UST_BYTECODE_NODE_TYPE_CAPTURE:
+               runtime->p.interpreter_funcs.capture = lttng_bytecode_capture_interpret_false;
+               break;
        default:
                abort();
        }
@@ -518,6 +524,16 @@ void lttng_bytecode_filter_sync_state(struct lttng_bytecode_runtime *runtime)
                runtime->interpreter_funcs.filter = lttng_bytecode_filter_interpret;
 }
 
+void lttng_bytecode_capture_sync_state(struct lttng_bytecode_runtime *runtime)
+{
+       struct lttng_ust_bytecode_node *bc = runtime->bc;
+
+       if (!bc->enabler->enabled || runtime->link_failed)
+               runtime->interpreter_funcs.capture = lttng_bytecode_capture_interpret_false;
+       else
+               runtime->interpreter_funcs.capture = lttng_bytecode_capture_interpret;
+}
+
 /*
  * Given the lists of bytecode programs of an instance (trigger or event) and
  * of a matching enabler, try to link all the enabler's bytecode programs with
index 57093a5573604b2634aff4aacb10c05426e3ede9..7f3e5ce8e87a9dd6e6b06dc5c2d592adcb721b8f 100644 (file)
@@ -335,6 +335,7 @@ struct lttng_interpreter_output {
 const char *print_op(enum bytecode_op op);
 
 void lttng_bytecode_filter_sync_state(struct lttng_bytecode_runtime *runtime);
+void lttng_bytecode_capture_sync_state(struct lttng_bytecode_runtime *runtime);
 
 int lttng_bytecode_validate(struct bytecode_runtime *bytecode);
 int lttng_bytecode_specialize(const struct lttng_event_desc *event_desc,
@@ -345,4 +346,11 @@ uint64_t lttng_bytecode_filter_interpret_false(void *filter_data,
 uint64_t lttng_bytecode_filter_interpret(void *filter_data,
                const char *filter_stack_data);
 
+uint64_t lttng_bytecode_capture_interpret_false(void *capture_data,
+               const char *capture_stack_data,
+               struct lttng_interpreter_output *output);
+uint64_t lttng_bytecode_capture_interpret(void *capture_data,
+               const char *capture_stack_data,
+               struct lttng_interpreter_output *output);
+
 #endif /* _LTTNG_BYTECODE_H */
index ac8b2b70f1e097f151d35ae7d7fe7a06914a52d8..66ec7b2ca7862715ca3295a179462266eaad4493 100644 (file)
@@ -826,6 +826,7 @@ int lttng_event_notifier_create(const struct lttng_event_desc *desc,
        event_notifier->registered = 0;
 
        CDS_INIT_LIST_HEAD(&event_notifier->filter_bytecode_runtime_head);
+       CDS_INIT_LIST_HEAD(&event_notifier->capture_bytecode_runtime_head);
        CDS_INIT_LIST_HEAD(&event_notifier->enablers_ref_head);
        event_notifier->desc = desc;
 
@@ -1368,9 +1369,11 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
                return NULL;
        event_notifier_enabler->base.format_type = format_type;
        CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.filter_bytecode_head);
+       CDS_INIT_LIST_HEAD(&event_notifier_enabler->capture_bytecode_head);
        CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.excluder_head);
 
        event_notifier_enabler->user_token = event_notifier_param->event.token;
+       event_notifier_enabler->num_captures = 0;
 
        memcpy(&event_notifier_enabler->base.event_param.name,
                event_notifier_param->event.name,
@@ -1475,6 +1478,20 @@ int lttng_event_notifier_enabler_attach_filter_bytecode(
        return 0;
 }
 
+int lttng_event_notifier_enabler_attach_capture_bytecode(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               struct lttng_ust_bytecode_node *bytecode)
+{
+       bytecode->enabler = lttng_event_notifier_enabler_as_enabler(
+                       event_notifier_enabler);
+       cds_list_add_tail(&bytecode->node,
+                       &event_notifier_enabler->capture_bytecode_head);
+       event_notifier_enabler->num_captures++;
+
+       lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+       return 0;
+}
+
 int lttng_event_notifier_enabler_attach_exclusion(
                struct lttng_event_notifier_enabler *event_notifier_enabler,
                struct lttng_ust_excluder_node *excluder)
@@ -1670,6 +1687,7 @@ void lttng_create_event_notifier_if_missing(
                        struct cds_hlist_node *node;
 
                        desc = probe_desc->event_desc[i];
+
                        if (!lttng_desc_match_enabler(desc,
                                        lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
                                continue;
@@ -1765,6 +1783,15 @@ int lttng_event_notifier_enabler_ref_event_notifiers(
                        &event_notifier_group->ctx,
                        &event_notifier->filter_bytecode_runtime_head,
                        &lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->filter_bytecode_head);
+
+               /*
+                * Link capture bytecodes if not linked yet.
+                */
+               lttng_enabler_link_bytecode(event_notifier->desc,
+                       &event_notifier_group->ctx, &event_notifier->capture_bytecode_runtime_head,
+                       &event_notifier_enabler->capture_bytecode_head);
+
+               event_notifier->num_captures = event_notifier_enabler->num_captures;
        }
 end:
        return 0;
@@ -1827,6 +1854,12 @@ void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group
                                &event_notifier->filter_bytecode_runtime_head, node) {
                        lttng_bytecode_filter_sync_state(runtime);
                }
+
+               /* Enable captures. */
+               cds_list_for_each_entry(runtime,
+                               &event_notifier->capture_bytecode_runtime_head, node) {
+                       lttng_bytecode_capture_sync_state(runtime);
+               }
        }
        __tracepoint_probe_prune_release_queue();
 }
index 4f32f55511acd25b860ab9c4a11eebde8ca9acf4..76fd7ea0a9361fbfe11937b6754398cf067ee6c7 100644 (file)
@@ -722,6 +722,10 @@ long lttng_event_notifier_enabler_cmd(int objd, unsigned int cmd, unsigned long
        case LTTNG_UST_EXCLUSION:
                return lttng_event_notifier_enabler_attach_exclusion(event_notifier_enabler,
                        (struct lttng_ust_excluder_node *) arg);
+       case LTTNG_UST_CAPTURE:
+               return lttng_event_notifier_enabler_attach_capture_bytecode(
+                       event_notifier_enabler,
+                       (struct lttng_ust_bytecode_node *) arg);
        case LTTNG_UST_ENABLE:
                return lttng_event_notifier_enabler_enable(event_notifier_enabler);
        case LTTNG_UST_DISABLE:
index ca51f7575ef4810ae15f8155e3678fbbd6ac842c..de03407b702aa5851f7fc69ae99633f5f08455f4 100644 (file)
@@ -748,6 +748,8 @@ static inline
 const char *bytecode_type_str(uint32_t cmd)
 {
        switch (cmd) {
+       case LTTNG_UST_CAPTURE:
+               return "capture";
        case LTTNG_UST_FILTER:
                return "filter";
        default:
@@ -775,6 +777,13 @@ int handle_bytecode_recv(struct sock_info *sock_info,
                reloc_offset = lum->u.filter.reloc_offset;
                seqnum = lum->u.filter.seqnum;
                break;
+       case LTTNG_UST_CAPTURE:
+               type = LTTNG_UST_BYTECODE_NODE_TYPE_CAPTURE;
+               data_size = lum->u.capture.data_size;
+               data_size_max = CAPTURE_BYTECODE_MAX_LEN;
+               reloc_offset = lum->u.capture.reloc_offset;
+               seqnum = lum->u.capture.seqnum;
+               break;
        default:
                abort();
        }
@@ -897,6 +906,7 @@ int handle_message(struct sock_info *sock_info,
                else
                        ret = lttng_ust_objd_unref(lum->handle, 1);
                break;
+       case LTTNG_UST_CAPTURE:
        case LTTNG_UST_FILTER:
                ret = handle_bytecode_recv(sock_info, sock, lum);
                if (ret)
index 0fc0b795de3e08179e98ada090ad963e0e1d6313..966fce6e7e120088c14327880584c9b8b30492e5 100644 (file)
@@ -46,13 +46,16 @@ struct lttng_event_enabler {
 
 struct lttng_event_notifier_enabler {
        struct lttng_enabler base;
-       struct cds_list_head node;      /* per-app list of event notifier enablers */
+       struct cds_list_head node;      /* per-app list of event_notifier enablers */
+       struct cds_list_head capture_bytecode_head;
        struct lttng_event_notifier_group *group; /* weak ref */
        uint64_t user_token;            /* User-provided token */
+       uint64_t num_captures;
 };
 
 enum lttng_ust_bytecode_node_type {
        LTTNG_UST_BYTECODE_NODE_TYPE_FILTER,
+       LTTNG_UST_BYTECODE_NODE_TYPE_CAPTURE,
 };
 
 struct lttng_ust_bytecode_node {
@@ -150,10 +153,11 @@ int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *enabler,
                struct lttng_ust_excluder_node *excluder);
 
 /*
- * Synchronize bytecodes for the enabler and the instance (event or trigger).
+ * Synchronize bytecodes for the enabler and the instance (event or
+ * event_notifier).
  *
  * This function goes over all bytecode programs of the enabler (event or
- * trigger enabler) to ensure each is linked to the provided instance.
+ * event_notifier enabler) to ensure each is linked to the provided instance.
  */
 LTTNG_HIDDEN
 void lttng_enabler_link_bytecode(const struct lttng_event_desc *event_desc,
@@ -221,6 +225,15 @@ int lttng_event_notifier_enabler_attach_filter_bytecode(
                struct lttng_event_notifier_enabler *event_notifier_enabler,
                struct lttng_ust_bytecode_node *bytecode);
 
+/*
+ * Attach capture bytecode program to `struct lttng_event_notifier_enabler` and
+ * all event_notifiers related to this enabler.
+ */
+LTTNG_HIDDEN
+int lttng_event_notifier_enabler_attach_capture_bytecode(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               struct lttng_ust_bytecode_node *bytecode);
+
 /*
  * Attach exclusion list to `struct lttng_event_notifier_enabler` and all
  * event notifiers related to this enabler.
This page took 0.036799 seconds and 4 git commands to generate.