bool coherent; /* Stream in a coherent state */
};
+struct lttng_kernel_event_pair {
+ /* Input */
+ char name[LTTNG_KERNEL_ABI_SYM_NAME_LEN];
+
+ /* Output from lttng_kernel_event_create() */
+ struct lttng_kernel_event_common *event[2];
+ int refcount;
+};
+
struct lttng_kernel_channel_buffer_ops_private {
struct lttng_kernel_channel_buffer_ops *pub; /* Public channel buffer ops interface */
#endif
#ifdef CONFIG_KRETPROBES
-int lttng_kretprobes_register(const char *name,
- const char *symbol_name,
+struct lttng_kernel_event_desc *lttng_create_kretprobes_event_desc(const char *name);
+int lttng_kretprobes_register(const char *symbol_name,
uint64_t offset,
uint64_t addr,
struct lttng_kernel_event_common *event_entry,
int enable);
#else
static inline
-int lttng_kretprobes_register(const char *name,
- const char *symbol_name,
+struct lttng_kernel_event_desc *lttng_create_kretprobes_event_desc(const char *name)
+{
+ return NULL;
+}
+static inline
+int lttng_kretprobes_register(const char *symbol_name,
uint64_t offset,
uint64_t addr,
struct lttng_kernel_event_common *event_entry,
void lttng_metadata_channel_buffer_destroy(struct lttng_kernel_channel_buffer *chan);
struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_enabler_common *event_enabler,
- const struct lttng_kernel_event_desc *event_desc);
+ const struct lttng_kernel_event_desc *event_desc,
+ struct lttng_kernel_event_pair *event_pair);
struct lttng_kernel_event_common *lttng_kernel_event_create(struct lttng_event_enabler_common *event_enabler,
- const struct lttng_kernel_event_desc *event_desc);
+ const struct lttng_kernel_event_desc *event_desc,
+ struct lttng_kernel_event_pair *event_pair);
int lttng_channel_enable(struct lttng_kernel_channel_common *channel);
int lttng_channel_disable(struct lttng_kernel_channel_common *channel);
case LTTNG_KERNEL_ABI_KPROBE:
lttng_fallthrough;
- case LTTNG_KERNEL_ABI_KRETPROBE:
- lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
{
struct lttng_kernel_event_common *event;
* We tolerate no failure path after event creation. It
* will stay invariant for the rest of the session.
*/
- event = lttng_kernel_event_create(&event_enabler->parent.parent, NULL);
+ event = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, NULL);
WARN_ON_ONCE(IS_ERR(event));
lttng_event_enabler_destroy(&event_enabler->parent.parent);
if (IS_ERR(event)) {
break;
}
+ case LTTNG_KERNEL_ABI_KRETPROBE:
+ {
+ struct lttng_kernel_event_common *event[2];
+ struct lttng_event_recorder_enabler *event_enabler;
+ struct lttng_kernel_event_pair event_pair;
+
+ if (strlen(event_param->name) + strlen("_entry") >= LTTNG_KERNEL_ABI_SYM_NAME_LEN)
+ return -EINVAL;
+
+ memset(&event_pair, 0, sizeof(event_pair));
+ event_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+ event_param, channel);
+ if (!event_enabler) {
+ ret = -ENOMEM;
+ goto event_error;
+ }
+
+ strcpy(event_pair.name, event_param->name);
+ strcat(event_pair.name, "_entry");
+ /*
+ * We tolerate no failure path after event creation. It
+ * will stay invariant for the rest of the session.
+ */
+ event[0] = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, &event_pair);
+ WARN_ON_ONCE(IS_ERR(event[0]));
+ if (IS_ERR(event[0])) {
+ lttng_event_enabler_destroy(&event_enabler->parent.parent);
+ ret = PTR_ERR(event[0]);
+ goto event_error;
+ }
+
+ strcpy(event_pair.name, event_param->name);
+ strcat(event_pair.name, "_exit");
+ event[1] = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, &event_pair);
+ WARN_ON_ONCE(IS_ERR(event[1]));
+
+ lttng_event_enabler_destroy(&event_enabler->parent.parent);
+ if (IS_ERR(event[1])) {
+ ret = PTR_ERR(event[1]);
+ goto event_error;
+ }
+ priv = event[0];
+ break;
+ }
+
case LTTNG_KERNEL_ABI_FUNCTION:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_NOOP:
case LTTNG_KERNEL_ABI_KPROBE:
lttng_fallthrough;
- case LTTNG_KERNEL_ABI_KRETPROBE:
- lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
{
struct lttng_kernel_event_common *event;
* We tolerate no failure path after event creation. It
* will stay invariant for the rest of the session.
*/
- event = lttng_kernel_event_create(&event_enabler->parent.parent, NULL);
+ event = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, NULL);
WARN_ON_ONCE(IS_ERR(event));
lttng_event_enabler_destroy(&event_enabler->parent.parent);
if (IS_ERR(event)) {
break;
}
+ case LTTNG_KERNEL_ABI_KRETPROBE:
+ {
+ struct lttng_kernel_event_common *event[2];
+ struct lttng_event_counter_enabler *event_enabler;
+ struct lttng_kernel_event_pair event_pair;
+
+ if (strlen(event_param->name) + strlen("_entry") >= LTTNG_KERNEL_ABI_SYM_NAME_LEN)
+ return -EINVAL;
+
+ memset(&event_pair, 0, sizeof(event_pair));
+ event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+ event_param, key_param, NULL, channel);
+ if (!event_enabler) {
+ ret = -ENOMEM;
+ goto event_error;
+ }
+
+ strcpy(event_pair.name, event_param->name);
+ strcat(event_pair.name, "_entry");
+ /*
+ * We tolerate no failure path after event creation. It
+ * will stay invariant for the rest of the session.
+ */
+ event[0] = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, &event_pair);
+ WARN_ON_ONCE(IS_ERR(event[0]));
+ if (IS_ERR(event[0])) {
+ lttng_event_enabler_destroy(&event_enabler->parent.parent);
+ ret = PTR_ERR(event[0]);
+ goto event_error;
+ }
+
+ strcpy(event_pair.name, event_param->name);
+ strcat(event_pair.name, "_exit");
+ event[1] = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, &event_pair);
+ WARN_ON_ONCE(IS_ERR(event[1]));
+
+ lttng_event_enabler_destroy(&event_enabler->parent.parent);
+ if (IS_ERR(event[1])) {
+ ret = PTR_ERR(event[1]);
+ goto event_error;
+ }
+ priv = event[0];
+ break;
+ }
+
case LTTNG_KERNEL_ABI_FUNCTION:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_NOOP:
ret = -ENOMEM;
goto event_notifier_error;
}
- event = lttng_kernel_event_create(&event_notifier_enabler->parent, NULL);
+ event = lttng_kernel_event_create(&event_notifier_enabler->parent, NULL, NULL);
WARN_ON_ONCE(IS_ERR(event));
lttng_event_enabler_destroy(&event_notifier_enabler->parent);
if (IS_ERR(event)) {
* Needs to be called with sessions mutex held.
*/
struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_enabler_common *event_enabler,
- const struct lttng_kernel_event_desc *event_desc)
+ const struct lttng_kernel_event_desc *event_desc,
+ struct lttng_kernel_event_pair *event_pair)
{
char key_string[LTTNG_KEY_TOKEN_STRING_LEN_MAX] = { 0 };
struct lttng_event_ht *events_name_ht = lttng_get_events_name_ht_from_enabler(event_enabler);
const char *event_name;
int ret;
- if (!lttng_kernel_event_id_available(event_enabler)) {
- ret = -EMFILE;
- goto full;
+ if (event_pair == NULL || event_pair->refcount == 0) {
+ if (!lttng_kernel_event_id_available(event_enabler)) {
+ ret = -EMFILE;
+ goto full;
+ }
}
switch (itype) {
lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
lttng_fallthrough;
- case LTTNG_KERNEL_ABI_KRETPROBE:
- lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
event_name = event_param->name;
break;
+ case LTTNG_KERNEL_ABI_KRETPROBE:
+ event_name = event_pair->name;
+ break;
+
case LTTNG_KERNEL_ABI_FUNCTION:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_NOOP:
case LTTNG_KERNEL_ABI_KRETPROBE:
{
- struct lttng_kernel_event_common *event_return;
-
- /* kretprobe defines 2 events */
/*
* Needs to be explicitly enabled after creation, since
* we may want to apply filters.
*/
event->enabled = 0;
event->priv->registered = 1;
-
- event_return = lttng_kernel_event_alloc(event_enabler, key_head, key_string);
- if (!event) {
+ event->priv->desc = lttng_create_kretprobes_event_desc(event_name);
+ if (!event->priv->desc) {
ret = -ENOMEM;
- goto alloc_error;
+ goto register_error;
}
+ event_pair->event[event_pair->refcount++] = event;
- event_return->enabled = 0;
- event_return->priv->registered = 1;
-
- /*
- * Populate lttng_event structure before kretprobe registration.
- */
- smp_wmb();
- ret = lttng_kretprobes_register(event_name,
- event_param->u.kretprobe.symbol_name,
- event_param->u.kretprobe.offset,
- event_param->u.kretprobe.addr,
- event, event_return);
- if (ret) {
- lttng_kernel_event_free(event_return);
- ret = -EINVAL;
- goto register_error;
+ /* kretprobe defines 2 events. */
+ if (event_pair->refcount == 2) {
+ /*
+ * Populate lttng_event structure before kretprobe registration.
+ */
+ smp_wmb();
+ ret = lttng_kretprobes_register(event_param->u.kretprobe.symbol_name,
+ event_param->u.kretprobe.offset,
+ event_param->u.kretprobe.addr,
+ event_pair->event[0], event_pair->event[1]);
+ if (ret) {
+ ret = -EINVAL;
+ goto register_error;
+ }
}
- /* Take 2 refs on the module: one per event. */
ret = try_module_get(event->priv->desc->owner);
WARN_ON_ONCE(!ret);
- ret = try_module_get(event_return->priv->desc->owner);
- WARN_ON_ONCE(!ret);
- ret = _lttng_event_recorder_metadata_statedump(event_return);
- WARN_ON_ONCE(ret > 0);
- if (ret) {
- lttng_kernel_event_free(event_return);
- module_put(event_return->priv->desc->owner);
- module_put(event->priv->desc->owner);
- goto statedump_error;
- }
- list_add(&event_return->priv->node, event_list_head);
- if (key_head) {
- struct lttng_kernel_event_counter_private *event_return_counter_priv =
- container_of(event_return->priv, struct lttng_kernel_event_counter_private, parent.parent);
- hlist_add_head(&event_return_counter_priv->hlist_key_node, key_head);
- }
ret = lttng_append_event_to_channel_map(event_enabler, event, event_name);
WARN_ON_ONCE(ret);
- ret = lttng_append_event_to_channel_map(event_enabler, event_return, event_name);
- WARN_ON_ONCE(ret);
break;
}
}
struct lttng_kernel_event_common *lttng_kernel_event_create(struct lttng_event_enabler_common *event_enabler,
- const struct lttng_kernel_event_desc *event_desc)
+ const struct lttng_kernel_event_desc *event_desc,
+ struct lttng_kernel_event_pair *event_pair)
{
struct lttng_kernel_event_common *event;
mutex_lock(&sessions_mutex);
- event = _lttng_kernel_event_create(event_enabler, event_desc);
+ event = _lttng_kernel_event_create(event_enabler, event_desc, event_pair);
mutex_unlock(&sessions_mutex);
return event;
}
/*
* We need to create an event for this event probe.
*/
- event = _lttng_kernel_event_create(event_enabler, desc);
+ event = _lttng_kernel_event_create(event_enabler, desc, NULL);
if (IS_ERR(event)) {
/* Skip if already found. */
if (PTR_ERR(event) == -EEXIST)
/*
* Create event description
*/
-static
-int lttng_create_kprobe_event(const char *name, struct lttng_kernel_event_common *event,
- enum lttng_kretprobe_type type)
+struct lttng_kernel_event_desc *lttng_create_kretprobes_event_desc(const char *name)
{
struct lttng_kernel_event_desc *desc;
char *alloc_name;
size_t name_len;
- const char *suffix = NULL;
- int ret;
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc)
- return -ENOMEM;
+ return NULL;
name_len = strlen(name);
- switch (type) {
- case EVENT_ENTRY:
- suffix = "_entry";
- break;
- case EVENT_EXIT:
- suffix = "_exit";
- break;
- }
- name_len += strlen(suffix);
alloc_name = kmalloc(name_len + 1, GFP_KERNEL);
- if (!alloc_name) {
- ret = -ENOMEM;
+ if (!alloc_name)
goto error_str;
- }
strcpy(alloc_name, name);
- strcat(alloc_name, suffix);
desc->event_name = alloc_name;
desc->tp_class = &tp_class;
desc->owner = THIS_MODULE;
- event->priv->desc = desc;
-
- return 0;
+ return desc;
error_str:
kfree(desc);
- return ret;
+ return NULL;
}
-int lttng_kretprobes_register(const char *name,
- const char *symbol_name,
+int lttng_kretprobes_register(const char *symbol_name,
uint64_t offset,
uint64_t addr,
struct lttng_kernel_event_common *event_entry,
if (symbol_name[0] == '\0')
symbol_name = NULL;
- ret = lttng_create_kprobe_event(name, event_entry, EVENT_ENTRY);
- if (ret)
- goto error;
- ret = lttng_create_kprobe_event(name, event_exit, EVENT_EXIT);
- if (ret)
- goto event_exit_error;
lttng_krp = kzalloc(sizeof(*lttng_krp), GFP_KERNEL);
if (!lttng_krp)
goto krp_error;
name_error:
kfree(lttng_krp);
krp_error:
- kfree(event_exit->priv->desc->event_name);
- kfree(event_exit->priv->desc);
-event_exit_error:
- kfree(event_entry->priv->desc->event_name);
- kfree(event_entry->priv->desc);
-error:
return ret;
}
WARN_ON_ONCE(!event_recorder_enabler);
if (!event_recorder_enabler)
return;
- event = _lttng_kernel_event_create(&event_recorder_enabler->parent.parent, desc);
+ event = _lttng_kernel_event_create(&event_recorder_enabler->parent.parent, desc, NULL);
WARN_ON_ONCE(IS_ERR(event));
lttng_event_enabler_destroy(&event_recorder_enabler->parent.parent);
if (IS_ERR(event)) {
event_notifier_enabler = lttng_event_notifier_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
&event_notifier_param, syscall_event_notifier_enabler->group);
WARN_ON_ONCE(!event_notifier_enabler);
- event = _lttng_kernel_event_create(&event_notifier_enabler->parent, desc);
+ event = _lttng_kernel_event_create(&event_notifier_enabler->parent, desc, NULL);
WARN_ON_ONCE(IS_ERR(event));
lttng_event_enabler_destroy(&event_notifier_enabler->parent);
if (IS_ERR(event)) {
WARN_ON_ONCE(!event_counter_enabler);
if (!event_counter_enabler)
return;
- event = _lttng_kernel_event_create(&event_counter_enabler->parent.parent, desc);
+ event = _lttng_kernel_event_create(&event_counter_enabler->parent.parent, desc, NULL);
lttng_event_enabler_destroy(&event_counter_enabler->parent.parent);
if (IS_ERR(event)) {
if (PTR_ERR(event) != -EEXIST)