kprobe: Implement kprobes with event enablers
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 1 Mar 2022 17:27:06 +0000 (12:27 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 15 Jul 2024 21:01:42 +0000 (17:01 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Idd1285baa8da6476620ddfc3c21d93a8d4ab08f7

include/lttng/events-internal.h
src/lttng-abi.c
src/lttng-events.c
src/lttng-kprobes.c

index d94d25415798b1727f4603ebdcabfeccac330fbc..eda1a7b23e8daf72f9c109a8f1e00d1d558f12b0 100644 (file)
@@ -89,6 +89,9 @@ struct lttng_uprobe_handler {
 struct lttng_kprobe {
        struct kprobe kp;
        char *symbol_name;
+       uint64_t addr;
+       uint64_t offset;
+       kprobe_pre_handler_t pre_handler;
 };
 
 struct lttng_uprobe {
@@ -1026,18 +1029,19 @@ static inline void lttng_syscall_table_set_wildcard_all(struct lttng_event_enabl
 #endif
 
 #ifdef CONFIG_KPROBES
-int lttng_kprobes_register_event(const char *name,
+int lttng_kprobes_init_event(const char *name,
                const char *symbol_name,
                uint64_t offset,
                uint64_t addr,
                struct lttng_kernel_event_common *event);
+int lttng_kprobes_register_event(struct lttng_kernel_event_common *event);
 void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event);
 void lttng_kprobes_destroy_event_private(struct lttng_kernel_event_common *event);
 int lttng_kprobes_match_check(const char *symbol_name, uint64_t offset, uint64_t addr);
 
 #else
 static inline
-int lttng_kprobes_register_event(const char *name,
+int lttng_kprobes_init_event(const char *name,
                const char *symbol_name,
                uint64_t offset,
                uint64_t addr,
@@ -1045,6 +1049,11 @@ int lttng_kprobes_register_event(const char *name,
 {
        return -ENOSYS;
 }
+static inline
+int lttng_kprobes_register_event(struct lttng_kernel_event_common *event)
+{
+       return -ENOSYS;
+}
 
 static inline
 void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
index 34f97e24e5a0101afce221a5b3d83d3184992b1c..e5b0339383500919871de4020d2bf7354bebef96 100644 (file)
@@ -2119,10 +2119,10 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                fops = &lttng_event_session_enabler_fops;
                break;
-       case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_KRETPROBE:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_UPROBE:
@@ -2185,7 +2185,17 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
        }
 
        case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
+       {
+               struct lttng_event_recorder_enabler *event_enabler;
+
+               event_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, channel);
+               if (event_enabler)
+                       lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
+               priv = event_enabler;
+               break;
+       }
+
        case LTTNG_KERNEL_ABI_UPROBE:
        {
                struct lttng_kernel_event_common *event;
@@ -2307,10 +2317,11 @@ int lttng_abi_create_event_counter_enabler(struct file *channel_file,
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                fops = &lttng_event_session_enabler_fops;
                break;
-       case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
+
        case LTTNG_KERNEL_ABI_KRETPROBE:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_UPROBE:
@@ -2373,7 +2384,17 @@ int lttng_abi_create_event_counter_enabler(struct file *channel_file,
        }
 
        case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
+       {
+               struct lttng_event_counter_enabler *event_enabler;
+
+               event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, key_param, NULL, channel);
+               if (event_enabler)
+                       lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
+               priv = event_enabler;
+               break;
+       }
+
        case LTTNG_KERNEL_ABI_UPROBE:
        {
                struct lttng_kernel_event_common *event;
@@ -2573,10 +2594,11 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                fops = &lttng_event_notifier_enabler_fops;
                break;
-       case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
+
        case LTTNG_KERNEL_ABI_KRETPROBE:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_UPROBE:
@@ -2659,7 +2681,17 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
        }
 
        case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
+       {
+               struct lttng_event_notifier_enabler *enabler;
+
+               enabler = lttng_event_notifier_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                                       event_notifier_param, event_notifier_group);
+               if (enabler)
+                       lttng_event_notifier_enabler_group_add(event_notifier_group, enabler);
+               priv = enabler;
+               break;
+       }
+
        case LTTNG_KERNEL_ABI_UPROBE:
        {
                struct lttng_kernel_event_common *event;
@@ -3374,8 +3406,19 @@ long lttng_event_enabler_ioctl(struct file *file, unsigned int cmd, unsigned lon
        case LTTNG_KERNEL_ABI_DISABLE:
                return lttng_event_enabler_disable(event_enabler);
        case LTTNG_KERNEL_ABI_FILTER:
-               return lttng_event_enabler_attach_filter_bytecode(event_enabler,
-                       (struct lttng_kernel_abi_filter_bytecode __user *) arg);
+               /*
+                * Filters are only supported by tracepoint and syscall instrumentation.
+                */
+               switch (event_enabler->event_param.instrumentation) {
+               case LTTNG_KERNEL_ABI_TRACEPOINT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_SYSCALL:
+                       return lttng_event_enabler_attach_filter_bytecode(event_enabler,
+                               (struct lttng_kernel_abi_filter_bytecode __user *) arg);
+
+               default:
+                       return -EINVAL;
+               }
        case LTTNG_KERNEL_ABI_ADD_CALLSITE:
                return -EINVAL;
        default:
index 860d8f7e0829a7addcdf2686bb3297a0c932bafd..49888e32b6994bf7eb8e81c64968aa9b4aa24496 100644 (file)
@@ -688,11 +688,11 @@ int lttng_event_enable(struct lttng_kernel_event_common *event)
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                ret = -EINVAL;
                break;
 
-       case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_UPROBE:
                WRITE_ONCE(event->enabled, 1);
                break;
@@ -747,11 +747,11 @@ int lttng_event_disable(struct lttng_kernel_event_common *event)
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                ret = -EINVAL;
                break;
 
-       case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_UPROBE:
                WRITE_ONCE(event->enabled, 0);
                break;
@@ -1469,18 +1469,10 @@ struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_
                break;
 
        case LTTNG_KERNEL_ABI_KPROBE:
-               /*
-                * Needs to be explicitly enabled after creation, since
-                * we may want to apply filters.
-                */
+               /* Event will be enabled by enabler sync. */
                event->enabled = 0;
-               event->priv->registered = 1;
-               /*
-                * Populate lttng_event structure before event
-                * registration.
-                */
-               smp_wmb();
-               ret = lttng_kprobes_register_event(event_name,
+               event->priv->registered = 0;
+               ret = lttng_kprobes_init_event(event_name,
                                event_param->u.kprobe.symbol_name,
                                event_param->u.kprobe.offset,
                                event_param->u.kprobe.addr,
@@ -1489,10 +1481,13 @@ struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_
                        ret = -EINVAL;
                        goto register_error;
                }
+               /*
+                * Populate lttng_event structure before event
+                * registration.
+                */
+               smp_wmb();
                ret = try_module_get(event->priv->desc->owner);
                WARN_ON_ONCE(!ret);
-               ret = lttng_append_event_to_channel_map(event_enabler, event, event_name);
-               WARN_ON_ONCE(ret);
                break;
 
        case LTTNG_KERNEL_ABI_KRETPROBE:
@@ -1674,7 +1669,7 @@ int lttng_kernel_counter_get_max_nr_elem(struct lttng_kernel_channel_counter *co
        return counter->ops->priv->counter_get_max_nr_elem(counter, max_nr_elem);
 }
 
-/* Only used for tracepoints and system calls for now. */
+/* Used for tracepoints, system calls, and kprobe. */
 static
 void register_event(struct lttng_kernel_event_common *event)
 {
@@ -1696,7 +1691,9 @@ void register_event(struct lttng_kernel_event_common *event)
                break;
 
        case LTTNG_KERNEL_ABI_KPROBE:
-               lttng_fallthrough;
+               ret = lttng_kprobes_register_event(event);
+               break;
+
        case LTTNG_KERNEL_ABI_UPROBE:
                ret = 0;
                break;
@@ -2231,6 +2228,19 @@ int lttng_desc_match_enabler_check(const struct lttng_kernel_event_desc *desc,
                }
                break;
 
+       case LTTNG_KERNEL_ABI_KPROBE:
+               desc_name = desc->event_name;
+               switch (enabler->format_type) {
+               case LTTNG_ENABLER_FORMAT_STAR_GLOB:
+                       return -EINVAL;
+               case LTTNG_ENABLER_FORMAT_NAME:
+                       return lttng_match_enabler_name(desc_name, enabler_name);
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+
        default:
                WARN_ON_ONCE(1);
                return -EINVAL;
@@ -2358,6 +2368,21 @@ void lttng_event_enabler_create_tracepoint_events_if_missing(struct lttng_event_
        }
 }
 
+/* Try to create the event associated with this kprobe enabler. */
+static
+void lttng_event_enabler_create_kprobe_event_if_missing(struct lttng_event_enabler_common *event_enabler)
+{
+       struct lttng_kernel_event_common *event;
+
+       event = _lttng_kernel_event_create(event_enabler, NULL, NULL);
+       if (IS_ERR(event)) {
+               if (PTR_ERR(event) != -EEXIST) {
+                       printk(KERN_INFO "LTTng: Unable to create kprobe event %s\n",
+                               event_enabler->event_param.name);
+               }
+       }
+}
+
 /*
  * Create event if it is missing and present in the list of tracepoint probes.
  * Should be called with sessions mutex held.
@@ -2377,6 +2402,10 @@ void lttng_event_enabler_create_events_if_missing(struct lttng_event_enabler_com
                WARN_ON_ONCE(ret);
                break;
 
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_event_enabler_create_kprobe_event_if_missing(event_enabler);
+               break;
+
        default:
                WARN_ON_ONCE(1);
                break;
@@ -2915,6 +2944,8 @@ bool lttng_get_event_enabled_state(struct lttng_kernel_event_common *event)
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                /* Enable events */
                list_for_each_entry(enabler_ref, &event->priv->enablers_ref_head, node) {
                        if (enabler_ref->ref->enabled) {
@@ -2958,6 +2989,8 @@ bool lttng_event_is_lazy_sync(struct lttng_kernel_event_common *event)
        case LTTNG_KERNEL_ABI_TRACEPOINT:
                lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
                return true;
 
        default:
index b2e96635158241bd80caeb3f2d3ff3e33501264e..cdaf68ac9d0ffdb550b1a83389589ab5fe15f734 100644 (file)
@@ -117,11 +117,39 @@ static const struct lttng_kernel_tracepoint_class tp_class = {
        .fields = event_fields,
 };
 
+static
+int lttng_kp_init(struct lttng_kprobe *lttng_kp, const char *symbol_name, uint64_t offset, uint64_t addr,
+               kprobe_pre_handler_t pre_handler)
+{
+       /* Kprobes expects a NULL symbol name if unused */
+       if (symbol_name[0] == '\0')
+               symbol_name = NULL;
+
+       lttng_kp->pre_handler = pre_handler;
+
+       if (symbol_name) {
+               lttng_kp->symbol_name =
+                       kzalloc(LTTNG_KERNEL_ABI_SYM_NAME_LEN * sizeof(char),
+                               GFP_KERNEL);
+               if (!lttng_kp->symbol_name)
+                       return -ENOMEM;
+               memcpy(lttng_kp->symbol_name, symbol_name,
+                      LTTNG_KERNEL_ABI_SYM_NAME_LEN * sizeof(char));
+       }
+
+       lttng_kp->offset = offset;
+       lttng_kp->addr = addr;
+       return 0;
+}
+
 /*
- * Create event description
+ * Initialize event
  */
-static
-int lttng_create_kprobe_event(const char *name, struct lttng_kernel_event_common *event)
+int lttng_kprobes_init_event(const char *name,
+               const char *symbol_name,
+               uint64_t offset,
+               uint64_t addr,
+               struct lttng_kernel_event_common *event)
 {
        struct lttng_kernel_event_desc *desc;
        int ret;
@@ -137,46 +165,22 @@ int lttng_create_kprobe_event(const char *name, struct lttng_kernel_event_common
        }
        desc->owner = THIS_MODULE;
        event->priv->desc = desc;
-
+       ret = lttng_kp_init(&event->priv->u.kprobe, symbol_name, offset, addr,
+                       lttng_kprobes_event_handler_pre);
+       if (ret)
+               goto error_init;
        return 0;
 
+error_init:
+       kfree(desc->event_name);
 error_str:
        kfree(desc);
        return ret;
 }
 
 static
-int _lttng_kprobes_register(const char *symbol_name,
-                          uint64_t offset,
-                          uint64_t addr,
-                          struct lttng_kprobe *lttng_kp,
-                          kprobe_pre_handler_t pre_handler)
+int _lttng_kprobes_register(struct lttng_kprobe *lttng_kp)
 {
-       int ret;
-
-       /* Kprobes expects a NULL symbol name if unused */
-       if (symbol_name[0] == '\0')
-               symbol_name = NULL;
-
-       memset(&lttng_kp->kp, 0, sizeof(lttng_kp->kp));
-       lttng_kp->kp.pre_handler = pre_handler;
-
-       if (symbol_name) {
-               lttng_kp->symbol_name =
-                       kzalloc(LTTNG_KERNEL_ABI_SYM_NAME_LEN * sizeof(char),
-                               GFP_KERNEL);
-               if (!lttng_kp->symbol_name) {
-                       ret = -ENOMEM;
-                       goto name_error;
-               }
-               memcpy(lttng_kp->symbol_name, symbol_name,
-                      LTTNG_KERNEL_ABI_SYM_NAME_LEN * sizeof(char));
-               lttng_kp->kp.symbol_name = lttng_kp->symbol_name;
-       }
-
-       lttng_kp->kp.offset = offset;
-       lttng_kp->kp.addr = (void *) (unsigned long) addr;
-
        /*
         * Ensure the memory we just allocated don't notify page faults.
         * Well.. kprobes itself puts the page fault handler on the blacklist,
@@ -184,42 +188,21 @@ int _lttng_kprobes_register(const char *symbol_name,
         */
        wrapper_vmalloc_sync_mappings();
 
-       ret = register_kprobe(&lttng_kp->kp);
-       if (ret)
-               goto register_error;
-
-       return 0;
-
-register_error:
-       kfree(lttng_kp->symbol_name);
-name_error:
-       return ret;
+       /*
+        * Populate struct kprobe on each registration because kprobe internally
+        * does destructive changes to its state (e.g. addr=NULL).
+        */
+       memset(&lttng_kp->kp, 0, sizeof(lttng_kp->kp));
+       lttng_kp->kp.symbol_name = lttng_kp->symbol_name;
+       lttng_kp->kp.addr = (void *)(unsigned long)lttng_kp->addr;
+       lttng_kp->kp.offset = lttng_kp->offset;
+       lttng_kp->kp.pre_handler = lttng_kp->pre_handler;
+       return register_kprobe(&lttng_kp->kp);
 }
 
-int lttng_kprobes_register_event(const char *name,
-                          const char *symbol_name,
-                          uint64_t offset,
-                          uint64_t addr,
-                          struct lttng_kernel_event_common *event)
+int lttng_kprobes_register_event(struct lttng_kernel_event_common *event)
 {
-       int ret;
-
-       ret = lttng_create_kprobe_event(name, event);
-       if (ret)
-               goto error;
-
-       ret = _lttng_kprobes_register(symbol_name, offset, addr,
-               &event->priv->u.kprobe, lttng_kprobes_event_handler_pre);
-       if (ret)
-               goto register_error;
-
-       return 0;
-
-register_error:
-       kfree(event->priv->desc->event_name);
-       kfree(event->priv->desc);
-error:
-       return ret;
+       return _lttng_kprobes_register(&event->priv->u.kprobe);
 }
 
 void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
@@ -230,15 +213,21 @@ void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
 int lttng_kprobes_match_check(const char *symbol_name, uint64_t offset, uint64_t addr)
 {
        struct lttng_kprobe lttng_kp;
-       int ret;
+       int ret = 0;
 
        memset(&lttng_kp, 0, sizeof(lttng_kp));
-       ret = _lttng_kprobes_register(symbol_name, offset, addr, &lttng_kp, NULL);
+       ret = lttng_kp_init(&lttng_kp, symbol_name, offset, addr, NULL);
        if (ret)
-               return -ENOENT;
+               return ret;
+       ret = _lttng_kprobes_register(&lttng_kp);
+       if (ret) {
+               ret = -ENOENT;
+               goto end;
+       }
        unregister_kprobe(&lttng_kp.kp);
+end:
        kfree(lttng_kp.symbol_name);
-       return 0;
+       return ret;
 
 }
 
This page took 0.035706 seconds and 4 git commands to generate.