char padding[LTTNG_KERNEL_EVENT_NOTIFIER_PADDING1];
} __attribute__((packed));
+#define LTTNG_KERNEL_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
+struct lttng_kernel_event_notifier_notification {
+ uint64_t token;
+ uint16_t capture_buf_size;
+ char padding[LTTNG_KERNEL_EVENT_NOTIFIER_NOTIFICATION_PADDING];
+} __attribute__((packed));
+
struct lttng_kernel_tracer_version {
uint32_t major;
uint32_t minor;
char data[0];
} __attribute__((packed));
+#define LTTNG_KERNEL_CAPTURE_BYTECODE_MAX_LEN 65536
+struct lttng_kernel_capture_bytecode {
+ uint32_t len;
+ uint32_t reloc_offset;
+ uint64_t seqnum;
+ char data[0];
+} __attribute__((packed));
+
enum lttng_kernel_tracker_type {
LTTNG_KERNEL_TRACKER_UNKNOWN = -1,
#define LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD \
_IO(0xF6, 0xB1)
+/* Event notifier file descriptor ioctl */
+#define LTTNG_KERNEL_CAPTURE _IO(0xF6, 0xB8)
+
/*
* LTTng-specific ioctls for the lib ringbuffer.
*
#include <lttng/events.h>
-void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier);
+void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *stack_data);
#endif /* _LTTNG_EVENT_NOTIFIER_NOTIFICATION_H */
enum lttng_bytecode_node_type {
LTTNG_BYTECODE_NODE_TYPE_FILTER,
+ LTTNG_BYTECODE_NODE_TYPE_CAPTURE,
};
struct lttng_bytecode_node {
/* Other bits are kept for future use. */
};
+struct lttng_interpreter_output;
+
struct lttng_bytecode_runtime {
/* Associated bytecode */
struct lttng_bytecode_node *bc;
uint64_t (*filter)(void *filter_data,
struct lttng_probe_ctx *lttng_probe_ctx,
const char *filter_stack_data);
+ uint64_t (*capture)(void *filter_data,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *capture_stack_data,
+ struct lttng_interpreter_output *output);
} interpreter_funcs;
int link_failed;
struct list_head node; /* list of bytecode runtime in event */
struct hlist_node hlist; /* session ht of event_notifiers */
/* list of struct lttng_bytecode_runtime, sorted by seqnum */
struct list_head filter_bytecode_runtime_head;
+ size_t num_captures;
+ struct list_head capture_bytecode_runtime_head;
int has_enablers_without_bytecode;
- void (*send_notification)(struct lttng_event_notifier *event_notifier);
+ void (*send_notification)(struct lttng_event_notifier *event_notifier,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *interpreter_stack_data);
struct lttng_event_notifier_group *group; /* Weak ref */
};
struct lttng_enabler base;
struct list_head node; /* List of event_notifier enablers */
struct lttng_event_notifier_group *group;
+
+ /* head list of struct lttng_bytecode_node */
+ struct list_head capture_bytecode_head;
+ uint64_t num_captures;
};
+
static inline
struct lttng_enabler *lttng_event_enabler_as_enabler(
struct lttng_event_enabler *event_enabler)
int lttng_event_notifier_enabler_attach_filter_bytecode(
struct lttng_event_notifier_enabler *event_notifier_enabler,
struct lttng_kernel_filter_bytecode __user *bytecode);
+int lttng_event_notifier_enabler_attach_capture_bytecode(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_kernel_capture_bytecode __user *bytecode);
void lttng_enabler_link_bytecode(const struct lttng_event_desc *event_desc,
struct lttng_ctx *ctx,
const char *lttng_bytecode_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,
struct bytecode_runtime *bytecode);
struct lttng_probe_ctx *lttng_probe_ctx,
const char *filter_stack_data);
+uint64_t lttng_bytecode_capture_interpret_false(void *capture_data,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *capture_stack_data,
+ struct lttng_interpreter_output *output);
+uint64_t lttng_bytecode_capture_interpret(void *capture_data,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *capture_stack_data,
+ struct lttng_interpreter_output *output);
+
#endif /* _LTTNG_FILTER_H */
#undef LTTNG_TRACEPOINT_EVENT_CLASS_CODE_NOARGS
#define LTTNG_TRACEPOINT_EVENT_CLASS_CODE_NOARGS(_name, _locvar, _code_pre, _fields, _code_post) \
static inline \
-void __event_prepare_filter_stack__##_name(char *__stack_data, \
+void __event_prepare_interpreter_stack__##_name(char *__stack_data, \
void *__tp_locvar) \
{ \
struct { _locvar } *tp_locvar __attribute__((unused)) = __tp_locvar; \
#undef LTTNG_TRACEPOINT_EVENT_CLASS_CODE
#define LTTNG_TRACEPOINT_EVENT_CLASS_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \
static inline \
-void __event_prepare_filter_stack__##_name(char *__stack_data, \
+void __event_prepare_interpreter_stack__##_name(char *__stack_data, \
void *__tp_locvar, _proto) \
{ \
struct { _locvar } *tp_locvar __attribute__((unused)) = __tp_locvar; \
struct lttng_bytecode_runtime *bc_runtime; \
int __filter_record = __event->has_enablers_without_bytecode; \
\
- __event_prepare_filter_stack__##_name(__stackvar.__filter_stack_data, \
+ __event_prepare_interpreter_stack__##_name(__stackvar.__filter_stack_data, \
tp_locvar, _args); \
lttng_list_for_each_entry_rcu(bc_runtime, &__event->filter_bytecode_runtime_head, node) { \
if (unlikely(bc_runtime->interpreter_funcs.filter(bc_runtime, &__lttng_probe_ctx, \
struct lttng_bytecode_runtime *bc_runtime; \
int __filter_record = __event->has_enablers_without_bytecode; \
\
- __event_prepare_filter_stack__##_name(__stackvar.__filter_stack_data, \
+ __event_prepare_interpreter_stack__##_name(__stackvar.__filter_stack_data, \
tp_locvar); \
lttng_list_for_each_entry_rcu(bc_runtime, &__event->filter_bytecode_runtime_head, node) { \
if (unlikely(bc_runtime->interpreter_funcs.filter(bc_runtime, &__lttng_probe_ctx, \
}; \
union { \
size_t __dynamic_len_removed[ARRAY_SIZE(__event_fields___##_name)]; \
- char __filter_stack_data[2 * sizeof(unsigned long) * ARRAY_SIZE(__event_fields___##_name)]; \
+ char __interpreter_stack_data[2 * sizeof(unsigned long) * ARRAY_SIZE(__event_fields___##_name)]; \
} __stackvar; \
struct probe_local_vars __tp_locvar; \
struct probe_local_vars *tp_locvar __attribute__((unused)) = \
return; \
_code_pre \
if (unlikely(!list_empty(&__event_notifier->filter_bytecode_runtime_head))) { \
- struct lttng_bytecode_runtime *bc_runtime; \
+ struct lttng_bytecode_runtime *bc_runtime; \
int __filter_record = __event_notifier->has_enablers_without_bytecode; \
- \
- __event_prepare_filter_stack__##_name(__stackvar.__filter_stack_data, \
- tp_locvar, _args); \
+ \
+ __event_prepare_interpreter_stack__##_name(__stackvar.__interpreter_stack_data, \
+ tp_locvar, _args); \
lttng_list_for_each_entry_rcu(bc_runtime, &__event_notifier->filter_bytecode_runtime_head, node) { \
- if (unlikely(bc_runtime->interpreter_funcs.filter(bc_runtime, &__lttng_probe_ctx, \
- __stackvar.__filter_stack_data) & LTTNG_INTERPRETER_RECORD_FLAG)) \
+ if (unlikely(bc_runtime->interpreter_funcs.filter(bc_runtime, &__lttng_probe_ctx, \
+ __stackvar.__interpreter_stack_data) & LTTNG_INTERPRETER_RECORD_FLAG)) \
__filter_record = 1; \
} \
if (likely(!__filter_record)) \
goto __post; \
} \
\
- __event_notifier->send_notification(__event_notifier); \
+ if (unlikely(!list_empty(&__event_notifier->capture_bytecode_runtime_head))) \
+ __event_prepare_interpreter_stack__##_name( \
+ __stackvar.__interpreter_stack_data, \
+ tp_locvar, _args); \
+ \
+ __event_notifier->send_notification(__event_notifier, \
+ &__lttng_probe_ctx, \
+ __stackvar.__interpreter_stack_data); \
+ \
__post: \
_code_post \
return; \
}; \
union { \
size_t __dynamic_len_removed[ARRAY_SIZE(__event_fields___##_name)]; \
- char __filter_stack_data[2 * sizeof(unsigned long) * ARRAY_SIZE(__event_fields___##_name)]; \
+ char __interpreter_stack_data[2 * sizeof(unsigned long) * ARRAY_SIZE(__event_fields___##_name)]; \
} __stackvar; \
struct probe_local_vars __tp_locvar; \
struct probe_local_vars *tp_locvar __attribute__((unused)) = \
if (unlikely(!READ_ONCE(__event_notifier->enabled))) \
return; \
_code_pre \
- if (unlikely(!list_empty(&__event_notifier->filter_bytecode_runtime_head))) { \
- struct lttng_bytecode_runtime *bc_runtime; \
- int __filter_record = __event_notifier->has_enablers_without_bytecode; \
- \
- __event_prepare_filter_stack__##_name(__stackvar.__filter_stack_data, \
- tp_locvar); \
+ if (unlikely(!list_empty(&__event_notifier->filter_bytecode_runtime_head))) { \
+ struct lttng_bytecode_runtime *bc_runtime; \
+ int __filter_record = __event_notifier->has_enablers_without_bytecode; \
+ \
+ __event_prepare_interpreter_stack__##_name(__stackvar.__interpreter_stack_data, \
+ tp_locvar); \
lttng_list_for_each_entry_rcu(bc_runtime, &__event_notifier->filter_bytecode_runtime_head, node) { \
- if (unlikely(bc_runtime->interpreter_funcs.filter(bc_runtime, &__lttng_probe_ctx, \
- __stackvar.__filter_stack_data) & LTTNG_INTERPRETER_RECORD_FLAG)) \
+ if (unlikely(bc_runtime->interpreter_funcs.filter(bc_runtime, &__lttng_probe_ctx, \
+ __stackvar.__interpreter_stack_data) & LTTNG_INTERPRETER_RECORD_FLAG)) \
__filter_record = 1; \
} \
if (likely(!__filter_record)) \
goto __post; \
} \
\
- __event_notifier->send_notification(__event_notifier); \
+ if (unlikely(!list_empty(&__event_notifier->capture_bytecode_runtime_head))) \
+ __event_prepare_interpreter_stack__##_name( \
+ __stackvar.__interpreter_stack_data, \
+ tp_locvar); \
+ \
+ __event_notifier->send_notification(__event_notifier, \
+ &__lttng_probe_ctx, \
+ __stackvar.__interpreter_stack_data); \
__post: \
_code_post \
return; \
WARN_ON_ONCE(1);
return -ENOSYS;
}
+
+ case LTTNG_KERNEL_CAPTURE:
+ switch (*evtype) {
+ case LTTNG_TYPE_EVENT:
+ return -EINVAL;
+ case LTTNG_TYPE_ENABLER:
+ event_notifier_enabler = file->private_data;
+ return lttng_event_notifier_enabler_attach_capture_bytecode(
+ event_notifier_enabler,
+ (struct lttng_kernel_capture_bytecode __user *) arg);
+ default:
+ WARN_ON_ONCE(1);
+ return -ENOSYS;
+ }
case LTTNG_KERNEL_ADD_CALLSITE:
switch (*evtype) {
case LTTNG_TYPE_EVENT:
return LTTNG_INTERPRETER_DISCARD;
}
+uint64_t lttng_bytecode_capture_interpret_false(void *filter_data,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *capture_stack_data,
+ struct lttng_interpreter_output *output)
+{
+ return LTTNG_INTERPRETER_DISCARD;
+}
+
#ifdef INTERPRETER_USE_SWITCH
/*
filter_stack_data, NULL);
}
+uint64_t lttng_bytecode_capture_interpret(void *capture_data,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *capture_stack_data,
+ struct lttng_interpreter_output *output)
+{
+ return bytecode_interpret(capture_data, lttng_probe_ctx,
+ capture_stack_data, output);
+}
+
#undef START_OP
#undef OP
#undef PO
case LTTNG_BYTECODE_NODE_TYPE_FILTER:
runtime->p.interpreter_funcs.filter = lttng_bytecode_filter_interpret;
break;
+ case LTTNG_BYTECODE_NODE_TYPE_CAPTURE:
+ runtime->p.interpreter_funcs.capture = lttng_bytecode_capture_interpret_false;
+ break;
default:
WARN_ON(1);
}
case LTTNG_BYTECODE_NODE_TYPE_FILTER:
runtime->p.interpreter_funcs.filter = lttng_bytecode_filter_interpret_false;
break;
+ case LTTNG_BYTECODE_NODE_TYPE_CAPTURE:
+ runtime->p.interpreter_funcs.capture = lttng_bytecode_capture_interpret_false;
+ break;
default:
WARN_ON(1);
}
runtime->interpreter_funcs.filter = lttng_bytecode_filter_interpret;
}
+void lttng_bytecode_capture_sync_state(struct lttng_bytecode_runtime *runtime)
+{
+ struct lttng_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
- * the instance.
+ * Given the lists of bytecode programs of an instance (event or event
+ * notifier) and of a matching enabler, try to link all the enabler's bytecode
+ * programs with the instance.
*
* This function is called after we confirmed that name enabler and the
* instance are matching names (or glob pattern matching).
#include <lttng/msgpack.h>
#include <lttng/event-notifier-notification.h>
-static
-int capture_enum(struct lttng_msgpack_writer *writer,
- struct lttng_interpreter_output *output) __attribute__ ((unused));
+/*
+ * FIXME: this probably too low but it needs to be below 1024 bytes to avoid
+ * the frame to be larger than the 1024 limit enforced by the kernel.
+ */
+#define CAPTURE_BUFFER_SIZE 512
+
+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
int capture_enum(struct lttng_msgpack_writer *writer,
struct lttng_interpreter_output *output)
return value;
}
-static
-int capture_sequence(struct lttng_msgpack_writer *writer,
- struct lttng_interpreter_output *output) __attribute__ ((unused));
int capture_sequence(struct lttng_msgpack_writer *writer,
struct lttng_interpreter_output *output)
{
return ret;
}
-void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier)
+static
+int notification_append_capture(
+ struct lttng_event_notifier_notification *notif,
+ struct lttng_interpreter_output *output)
+{
+ struct lttng_msgpack_writer *writer = ¬if->writer;
+ int ret = 0;
+
+ switch (output->type) {
+ case LTTNG_INTERPRETER_TYPE_S64:
+ ret = lttng_msgpack_write_signed_integer(writer, output->u.s);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+ break;
+ case LTTNG_INTERPRETER_TYPE_U64:
+ ret = lttng_msgpack_write_unsigned_integer(writer, output->u.u);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+ break;
+ case LTTNG_INTERPRETER_TYPE_STRING:
+ ret = lttng_msgpack_write_str(writer, output->u.str.str);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+ break;
+ case LTTNG_INTERPRETER_TYPE_SEQUENCE:
+ ret = capture_sequence(writer, output);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+ break;
+ case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
+ case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
+ ret = capture_enum(writer, output);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+ break;
+ default:
+ ret = -1;
+ WARN_ON(1);
+ }
+end:
+ return ret;
+}
+
+static
+int notification_append_empty_capture(
+ struct lttng_event_notifier_notification *notif)
+{
+ int ret = lttng_msgpack_write_nil(¬if->writer);
+ if (ret)
+ WARN_ON_ONCE(1);
+
+ return ret;
+}
+
+static
+int notification_init(struct lttng_event_notifier_notification *notif,
+ struct lttng_event_notifier *event_notifier)
+{
+ struct lttng_msgpack_writer *writer = ¬if->writer;
+ int ret = 0;
+
+ notif->has_captures = false;
+
+ if (event_notifier->num_captures > 0) {
+ lttng_msgpack_writer_init(writer, notif->capture_buf,
+ CAPTURE_BUFFER_SIZE);
+
+ ret = lttng_msgpack_begin_array(writer, event_notifier->num_captures);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+
+ notif->has_captures = true;
+ }
+
+end:
+ return ret;
+}
+
+static
+void notification_send(struct lttng_event_notifier_notification *notif,
+ struct lttng_event_notifier *event_notifier)
{
struct lttng_event_notifier_group *event_notifier_group = event_notifier->group;
struct lib_ring_buffer_ctx ctx;
+ struct lttng_kernel_event_notifier_notification kernel_notif;
+ size_t capture_buffer_content_len, reserve_size;
int ret;
- if (unlikely(!READ_ONCE(event_notifier->enabled)))
- return;
+ reserve_size = sizeof(kernel_notif);
+ kernel_notif.token = event_notifier->user_token;
- lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL,
- sizeof(event_notifier->user_token),
- lttng_alignof(event_notifier->user_token), -1);
+ if (notif->has_captures) {
+ capture_buffer_content_len = notif->writer.write_pos - notif->writer.buffer;
+ } else {
+ capture_buffer_content_len = 0;
+ }
+
+ WARN_ON_ONCE(capture_buffer_content_len > CAPTURE_BUFFER_SIZE);
+
+ reserve_size += capture_buffer_content_len;
+ kernel_notif.capture_buf_size = capture_buffer_content_len;
+
+ lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL, reserve_size,
+ lttng_alignof(kernel_notif), -1);
ret = event_notifier_group->ops->event_reserve(&ctx, 0);
if (ret < 0) {
//TODO: error handling with counter maps
WARN_ON_ONCE(1);
return;
}
- lib_ring_buffer_align_ctx(&ctx, lttng_alignof(event_notifier->user_token));
- event_notifier_group->ops->event_write(&ctx, &event_notifier->user_token,
- sizeof(event_notifier->user_token));
+
+ lib_ring_buffer_align_ctx(&ctx, lttng_alignof(kernel_notif));
+
+ /* Write the notif structure. */
+ event_notifier_group->ops->event_write(&ctx, &kernel_notif,
+ sizeof(kernel_notif));
+
+ /*
+ * Write the capture buffer. No need to realigned as the below is a raw
+ * char* buffer.
+ */
+ event_notifier_group->ops->event_write(&ctx, ¬if->capture_buf,
+ capture_buffer_content_len);
+
event_notifier_group->ops->event_commit(&ctx);
irq_work_queue(&event_notifier_group->wakeup_pending);
}
+
+void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier,
+ struct lttng_probe_ctx *lttng_probe_ctx,
+ const char *stack_data)
+{
+ struct lttng_event_notifier_notification notif = { 0 };
+ int ret;
+
+ if (unlikely(!READ_ONCE(event_notifier->enabled)))
+ return;
+
+ ret = notification_init(¬if, event_notifier);
+ if (ret) {
+ WARN_ON_ONCE(1);
+ goto end;
+ }
+
+ if (unlikely(!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.
+ */
+ 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,
+ lttng_probe_ctx, stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG)
+ ret = notification_append_capture(¬if, &output);
+ else
+ ret = notification_append_empty_capture(¬if);
+
+ if (ret)
+ printk(KERN_WARNING "Error appending capture to notification");
+ }
+ }
+
+ /*
+ * Send the notification (including the capture buffer) to the
+ * sessiond.
+ */
+ notification_send(¬if, event_notifier);
+end:
+ return;
+}
event_notifier->group = event_notifier_group;
event_notifier->user_token = token;
+ event_notifier->num_captures = 0;
event_notifier->filter = filter;
event_notifier->instrumentation = itype;
event_notifier->evtype = LTTNG_TYPE_EVENT;
event_notifier->send_notification = lttng_event_notifier_notification_send;
INIT_LIST_HEAD(&event_notifier->filter_bytecode_runtime_head);
+ INIT_LIST_HEAD(&event_notifier->capture_bytecode_runtime_head);
INIT_LIST_HEAD(&event_notifier->enablers_ref_head);
switch (itype) {
lttng_enabler_link_bytecode(event_notifier->desc,
lttng_static_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,
+ lttng_static_ctx, &event_notifier->capture_bytecode_runtime_head,
+ &event_notifier_enabler->capture_bytecode_head);
+
+ event_notifier->num_captures = event_notifier_enabler->num_captures;
}
return 0;
}
event_notifier_enabler->base.format_type = format_type;
INIT_LIST_HEAD(&event_notifier_enabler->base.filter_bytecode_head);
+ INIT_LIST_HEAD(&event_notifier_enabler->capture_bytecode_head);
+
+ event_notifier_enabler->num_captures = 0;
memcpy(&event_notifier_enabler->base.event_param, &event_notifier_param->event,
sizeof(event_notifier_enabler->base.event_param));
return ret;
}
+int lttng_event_notifier_enabler_attach_capture_bytecode(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_kernel_capture_bytecode __user *bytecode)
+{
+ struct lttng_bytecode_node *bytecode_node;
+ struct lttng_enabler *enabler =
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler);
+ uint32_t bytecode_len;
+ int ret;
+
+ ret = get_user(bytecode_len, &bytecode->len);
+ if (ret)
+ return ret;
+
+ bytecode_node = lttng_kvzalloc(sizeof(*bytecode_node) + bytecode_len,
+ GFP_KERNEL);
+ if (!bytecode_node)
+ return -ENOMEM;
+
+ ret = copy_from_user(&bytecode_node->bc, bytecode,
+ sizeof(*bytecode) + bytecode_len);
+ if (ret)
+ goto error_free;
+
+ bytecode_node->type = LTTNG_BYTECODE_NODE_TYPE_CAPTURE;
+ bytecode_node->enabler = enabler;
+
+ /* Enforce length based on allocated size */
+ bytecode_node->bc.len = bytecode_len;
+ list_add_tail(&bytecode_node->node, &event_notifier_enabler->capture_bytecode_head);
+
+ event_notifier_enabler->num_captures++;
+
+ lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+ goto end;
+
+error_free:
+ lttng_kvfree(bytecode_node);
+end:
+ return ret;
+}
+
int lttng_event_notifier_add_callsite(struct lttng_event_notifier *event_notifier,
struct lttng_kernel_event_callsite __user *callsite)
{
list_for_each_entry(runtime,
&event_notifier->filter_bytecode_runtime_head, node)
lttng_bytecode_filter_sync_state(runtime);
+
+ /* Enable captures */
+ list_for_each_entry(runtime,
+ &event_notifier->capture_bytecode_runtime_head, node)
+ lttng_bytecode_capture_sync_state(runtime);
}
}
* Copyright (C) 2010-2020 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*/
+#include <linux/limits.h>
#include <linux/module.h>
#include <linux/types.h>
#include <wrapper/vmalloc.h> /* for wrapper_vmalloc_sync_mappings() */
+#include <lttng/abi.h>
#include <lttng/events.h>
#include <lttng/tracer.h>
};
struct event_notifier_record_header {
+ uint32_t payload_len; /* in bytes */
uint8_t header_end[0]; /* End of header */
};
struct lib_ring_buffer_ctx *ctx,
void *client_ctx)
{
- return 0;
+ size_t orig_offset = offset;
+ size_t padding;
+
+ padding = lib_ring_buffer_align(offset, lttng_alignof(uint32_t));
+ offset += padding;
+
+ offset += sizeof(uint32_t);
+
+ *pre_header_padding = padding;
+
+ return offset - orig_offset;
}
#include <ringbuffer/api.h>
struct lib_ring_buffer_ctx *ctx,
void *client_ctx)
{
- return 0;
+ return record_header_size(config, chan, offset,
+ pre_header_padding, ctx, client_ctx);
}
/**
offsetof(struct event_notifier_record_header, header_end));
CHAN_WARN_ON(chan, ret != offsetof(struct event_notifier_record_header, header_end));
*header_len = offsetof(struct event_notifier_record_header, header_end);
- /*
- * Currently, only 64-bit event notifier ID.
- */
- *payload_len = sizeof(uint64_t);
+ *payload_len = header.payload_len;
*timestamp = 0;
}
lib_ring_buffer_release_read(buf);
}
+static
+void lttng_write_event_notifier_header(const struct lib_ring_buffer_config *config,
+ struct lib_ring_buffer_ctx *ctx)
+{
+ uint32_t data_size;
+
+ WARN_ON_ONCE(ctx->data_size > U32_MAX);
+
+ data_size = (uint32_t) ctx->data_size;
+
+ lib_ring_buffer_write(config, ctx, &data_size, sizeof(data_size));
+
+ lib_ring_buffer_align_ctx(ctx, ctx->largest_align);
+}
+
static
int lttng_event_reserve(struct lib_ring_buffer_ctx *ctx, uint32_t event_id)
{
return ret;
lib_ring_buffer_backend_get_pages(&client_config, ctx,
&ctx->backend_pages);
+
+ lttng_write_event_notifier_header(&client_config, ctx);
return 0;
}
if (unlikely(!READ_ONCE(event_notifier->enabled)))
return 0;
- event_notifier->send_notification(event_notifier);
+ event_notifier->send_notification(event_notifier, NULL, NULL);
return 0;
}
if (unlikely(!READ_ONCE(event_notifier->enabled)))
return 0;
- event_notifier->send_notification(event_notifier);
+ event_notifier->send_notification(event_notifier, NULL, NULL);
return 0;
}