From: Francis Deslauriers Date: Mon, 6 Apr 2020 18:59:08 +0000 (-0400) Subject: Implement capturing payload on event notifiers X-Git-Tag: v2.13.0-rc1~432 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=d37ecb3fc622dee6f80f84c21f38d32eef407262;p=lttng-ust.git Implement capturing payload on event notifiers 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 Signed-off-by: Mathieu Desnoyers Change-Id: Ia3023a4f5c0aec014b37b72f92d1a924c7eff6a2 --- diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 302e6a36..1c80c144 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -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 diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index a4d54c42..35b73342 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -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); diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 5bd15838..44b8d4c4 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -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, diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 1f8be1a9..0a397e50 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -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 diff --git a/include/ust-comm.h b/include/ust-comm.h index c9c8ca41..fbaef544 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -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; diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index 744f66ba..b2fa8258 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -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) { diff --git a/liblttng-ust/event-notifier-notification.c b/liblttng-ust/event-notifier-notification.c index 844438f2..6fce4357 100644 --- a/liblttng-ust/event-notifier-notification.c +++ b/liblttng-ust/event-notifier-notification.c @@ -30,9 +30,24 @@ #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 = ¬if->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 = ¬if->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(¬if->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, ¬if, - 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(¬if, 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(¬if, &output); + else + notification_append_empty_capture(¬if); + } + } + + /* + * Send the notification (including the capture buffer) to the + * sessiond. + */ + notification_send(¬if); +} diff --git a/liblttng-ust/lttng-bytecode-interpreter.c b/liblttng-ust/lttng-bytecode-interpreter.c index ea5eca19..bba3cac8 100644 --- a/liblttng-ust/lttng-bytecode-interpreter.c +++ b/liblttng-ust/lttng-bytecode-interpreter.c @@ -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 diff --git a/liblttng-ust/lttng-bytecode.c b/liblttng-ust/lttng-bytecode.c index a6527ff1..30d3cbd1 100644 --- a/liblttng-ust/lttng-bytecode.c +++ b/liblttng-ust/lttng-bytecode.c @@ -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 diff --git a/liblttng-ust/lttng-bytecode.h b/liblttng-ust/lttng-bytecode.h index 57093a55..7f3e5ce8 100644 --- a/liblttng-ust/lttng-bytecode.h +++ b/liblttng-ust/lttng-bytecode.h @@ -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 */ diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index ac8b2b70..66ec7b2c 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -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, <tng_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(); } diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 4f32f555..76fd7ea0 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -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: diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index ca51f757..de03407b 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -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) diff --git a/liblttng-ust/ust-events-internal.h b/liblttng-ust/ust-events-internal.h index 0fc0b795..966fce6e 100644 --- a/liblttng-ust/ust-events-internal.h +++ b/liblttng-ust/ust-events-internal.h @@ -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.