kretprobes: implement event counter support
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 28 Feb 2022 19:15:00 +0000 (14:15 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 15 Jul 2024 20:58:48 +0000 (16:58 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Id5142ae8d31bba2c9a806f75cbbfefdca303d523

include/lttng/events-internal.h
src/lttng-abi.c
src/lttng-events.c
src/lttng-kretprobes.c
src/lttng-syscalls.c

index b3f938bbf695eb0b0f809779c37944929c985715..14ad198cdbf0441390538ee9bb7f8628b16d2f3b 100644 (file)
@@ -455,6 +455,15 @@ struct lttng_metadata_stream {
        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 */
 
@@ -1083,8 +1092,8 @@ void lttng_uprobes_destroy_event_private(struct lttng_kernel_event_common *event
 #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,
@@ -1095,8 +1104,12 @@ int lttng_kretprobes_event_enable_state(struct lttng_kernel_event_common *event,
        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,
@@ -1181,9 +1194,11 @@ struct lttng_kernel_channel_buffer *lttng_global_channel_create(struct lttng_ker
 
 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);
index 2675414ef4cb4f4aec0b710ebf437d3d00db9d24..17041bc3bd2c74c096430aada34768499a1cc7a5 100644 (file)
@@ -2008,8 +2008,6 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
 
        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;
@@ -2025,7 +2023,7 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
                 * 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)) {
@@ -2036,6 +2034,51 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
                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:
@@ -2153,8 +2196,6 @@ int lttng_abi_create_event_counter_enabler(struct file *channel_file,
 
        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;
@@ -2170,7 +2211,7 @@ int lttng_abi_create_event_counter_enabler(struct file *channel_file,
                 * 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)) {
@@ -2181,6 +2222,51 @@ int lttng_abi_create_event_counter_enabler(struct file *channel_file,
                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:
@@ -2420,7 +2506,7 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
                        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)) {
index bbf329dab3cca0c753bf5b0930353510664e4d3d..97c123b2c4d04ec6b9ffaf8b7dfaac099e7d1395 100644 (file)
@@ -1396,7 +1396,8 @@ int lttng_append_event_to_channel_map(struct lttng_event_enabler_common *event_e
  * 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);
@@ -1410,9 +1411,11 @@ struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_
        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) {
@@ -1424,12 +1427,14 @@ struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_
                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:
@@ -1506,62 +1511,38 @@ struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_
 
        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;
        }
 
@@ -1662,12 +1643,13 @@ full:
 }
 
 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;
 }
@@ -2378,7 +2360,7 @@ void lttng_event_enabler_create_tracepoint_events_if_missing(struct lttng_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)
index b1f4f7f805d5d6fec6b33c2ff74f6903fcc70e32..1b8bbb0acacf8319d6b5e984fb7341aff1263be1 100644 (file)
@@ -152,50 +152,31 @@ static const struct lttng_kernel_tracepoint_class tp_class = {
 /*
  * 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,
@@ -208,12 +189,6 @@ int lttng_kretprobes_register(const char *name,
        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;
@@ -266,12 +241,6 @@ register_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;
 }
 
index 415cb57f5b351809b88a7c0b053bc9d8d2c15ddf..aef50c4682b038c060d2b5ce3868fec511172ced 100644 (file)
@@ -577,7 +577,7 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                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)) {
@@ -624,7 +624,7 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                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)) {
@@ -669,7 +669,7 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                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)
This page took 0.033857 seconds and 4 git commands to generate.