Implement event notifiers for kprobes
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Tue, 14 Jan 2020 20:12:28 +0000 (15:12 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 18 Nov 2020 18:14:37 +0000 (13:14 -0500)
Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I69075c51f9df4ae89457967d96863dcf370d4570

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

index f89fe1d01fcb54c0177ae12dae01a21678d3af9c..cf04a30585dc3f0839e1dd9937f672f9477c5893 100644 (file)
@@ -344,6 +344,7 @@ struct lttng_event_notifier {
 
        enum lttng_kernel_instrumentation instrumentation;
        union {
+               struct lttng_kprobe kprobe;
        } u;
 
        /* Backward references: list of lttng_enabler_ref (ref to enablers) */
@@ -723,6 +724,9 @@ int lttng_channel_disable(struct lttng_channel *channel);
 int lttng_event_enable(struct lttng_event *event);
 int lttng_event_disable(struct lttng_event *event);
 
+int lttng_event_notifier_enable(struct lttng_event_notifier *event_notifier);
+int lttng_event_notifier_disable(struct lttng_event_notifier *event_notifier);
+
 void lttng_transport_register(struct lttng_transport *transport);
 void lttng_transport_unregister(struct lttng_transport *transport);
 
@@ -1016,6 +1020,12 @@ int lttng_kprobes_register_event(const char *name,
                struct lttng_event *event);
 void lttng_kprobes_unregister_event(struct lttng_event *event);
 void lttng_kprobes_destroy_event_private(struct lttng_event *event);
+int lttng_kprobes_register_event_notifier(const char *symbol_name,
+               uint64_t offset,
+               uint64_t addr,
+               struct lttng_event_notifier *event_notifier);
+void lttng_kprobes_unregister_event_notifier(struct lttng_event_notifier *event_notifier);
+void lttng_kprobes_destroy_event_notifier_private(struct lttng_event_notifier *event_notifier);
 #else
 static inline
 int lttng_kprobes_register_event(const char *name,
@@ -1038,7 +1048,21 @@ void lttng_kprobes_destroy_event_private(struct lttng_event *event)
 }
 
 static inline
-void lttng_kprobes_destroy_private(struct lttng_event *event)
+int lttng_kprobes_register_event_notifier(const char *symbol_name,
+               uint64_t offset,
+               uint64_t addr,
+               struct lttng_event_notifier *event_notifier)
+{
+       return -ENOSYS;
+}
+
+static inline
+void lttng_kprobes_unregister_event_notifier(struct lttng_event_notifier *event_notifier)
+{
+}
+
+static inline
+void lttng_kprobes_destroy_event_notifier_private(struct lttng_event_notifier *event_notifier)
 {
 }
 #endif
index 775f141714724224c4178e2288acda5da2c66101..7001aa0e9237e0729512855a295ae42ff9a16b93 100644 (file)
@@ -1711,6 +1711,7 @@ fd_error:
 static
 long lttng_event_notifier_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct lttng_event_notifier *event_notifier;
        struct lttng_event_notifier_enabler *event_notifier_enabler;
        enum lttng_event_type *evtype = file->private_data;
 
@@ -1718,7 +1719,8 @@ long lttng_event_notifier_ioctl(struct file *file, unsigned int cmd, unsigned lo
        case LTTNG_KERNEL_ENABLE:
                switch (*evtype) {
                case LTTNG_TYPE_EVENT:
-                       return -EINVAL;
+                       event_notifier = file->private_data;
+                       return lttng_event_notifier_enable(event_notifier);
                case LTTNG_TYPE_ENABLER:
                        event_notifier_enabler = file->private_data;
                        return lttng_event_notifier_enabler_enable(event_notifier_enabler);
@@ -1729,7 +1731,8 @@ long lttng_event_notifier_ioctl(struct file *file, unsigned int cmd, unsigned lo
        case LTTNG_KERNEL_DISABLE:
                switch (*evtype) {
                case LTTNG_TYPE_EVENT:
-                       return -EINVAL;
+                       event_notifier = file->private_data;
+                       return lttng_event_notifier_disable(event_notifier);
                case LTTNG_TYPE_ENABLER:
                        event_notifier_enabler = file->private_data;
                        return lttng_event_notifier_enabler_disable(event_notifier_enabler);
@@ -1806,6 +1809,8 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
        case LTTNG_KERNEL_TRACEPOINT:
                break;
        case LTTNG_KERNEL_KPROBE:
+               event_notifier_param->event.u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+               break;
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
index 41bbd7098ddae75f57c7df7a9ee61bddbc0f1258..84ffd28332e9b5b02a1cafed7d83f82e9249cff3 100644 (file)
@@ -614,8 +614,10 @@ int lttng_event_notifier_enable(struct lttng_event_notifier *event_notifier)
        case LTTNG_KERNEL_TRACEPOINT:
                ret = -EINVAL;
                break;
-       case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_KPROBE:
+               WRITE_ONCE(event_notifier->enabled, 1);
+               break;
+       case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_FUNCTION:
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_NOOP:
@@ -642,8 +644,10 @@ int lttng_event_notifier_disable(struct lttng_event_notifier *event_notifier)
        case LTTNG_KERNEL_TRACEPOINT:
                ret = -EINVAL;
                break;
-       case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_KPROBE:
+               WRITE_ONCE(event_notifier->enabled, 0);
+               break;
+       case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_FUNCTION:
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_NOOP:
@@ -1004,6 +1008,8 @@ struct lttng_event_notifier *_lttng_event_notifier_create(
                event_name = event_desc->name;
                break;
        case LTTNG_KERNEL_KPROBE:
+               event_name = event_notifier_param->event.name;
+               break;
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -1057,6 +1063,29 @@ struct lttng_event_notifier *_lttng_event_notifier_create(
                smp_wmb();
                break;
        case LTTNG_KERNEL_KPROBE:
+               /*
+                * Needs to be explicitly enabled after creation, since
+                * we may want to apply filters.
+                */
+               event_notifier->enabled = 0;
+               event_notifier->registered = 1;
+               /*
+                * Populate lttng_event_notifier structure before event
+                * registration.
+                */
+               smp_wmb();
+               ret = lttng_kprobes_register_event_notifier(
+                               event_notifier_param->event.u.kprobe.symbol_name,
+                               event_notifier_param->event.u.kprobe.offset,
+                               event_notifier_param->event.u.kprobe.addr,
+                               event_notifier);
+               if (ret) {
+                       ret = -EINVAL;
+                       goto register_error;
+               }
+               ret = try_module_get(event_notifier->desc->owner);
+               WARN_ON_ONCE(!ret);
+               break;
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -1206,8 +1235,10 @@ void register_event_notifier(struct lttng_event_notifier *event_notifier)
                                                  desc->event_notifier_callback,
                                                  event_notifier);
                break;
-       case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_KPROBE:
+               ret = 0;
+               break;
+       case LTTNG_KERNEL_SYSCALL:
        case LTTNG_KERNEL_UPROBE:
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
@@ -1237,6 +1268,9 @@ int _lttng_event_notifier_unregister(
                                                  event_notifier);
                break;
        case LTTNG_KERNEL_KPROBE:
+               lttng_kprobes_unregister_event_notifier(event_notifier);
+               ret = 0;
+               break;
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
        case LTTNG_KERNEL_SYSCALL:
@@ -1295,6 +1329,9 @@ void _lttng_event_notifier_destroy(struct lttng_event_notifier *event_notifier)
                lttng_event_desc_put(event_notifier->desc);
                break;
        case LTTNG_KERNEL_KPROBE:
+               module_put(event_notifier->desc->owner);
+               lttng_kprobes_destroy_event_notifier_private(event_notifier);
+               break;
        case LTTNG_KERNEL_KRETPROBE:
        case LTTNG_KERNEL_FUNCTION:
        case LTTNG_KERNEL_NOOP:
index 3f9b02356740055f146fcadf6b77004c62e5a096..4e80f1ef62e3acf5ae61c949c8a5af3be7eb4a25 100644 (file)
@@ -49,6 +49,20 @@ int lttng_kprobes_event_handler_pre(struct kprobe *p, struct pt_regs *regs)
        return 0;
 }
 
+static
+int lttng_kprobes_event_notifier_handler_pre(struct kprobe *p, struct pt_regs *regs)
+{
+       struct lttng_event_notifier *event_notifier =
+               container_of(p, struct lttng_event_notifier, u.kprobe.kp);
+
+       if (unlikely(!READ_ONCE(event_notifier->enabled)))
+               return 0;
+
+       event_notifier->send_notification(event_notifier);
+
+       return 0;
+}
+
 /*
  * Create event description
  */
@@ -94,6 +108,35 @@ error_str:
        return ret;
 }
 
+/*
+ * Create event_notifier description
+ */
+static
+int lttng_create_kprobe_event_notifier(const char *name, struct lttng_event_notifier *event_notifier)
+{
+       struct lttng_event_desc *desc;
+       int ret;
+
+       desc = kzalloc(sizeof(*event_notifier->desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+       desc->name = kstrdup(name, GFP_KERNEL);
+       if (!desc->name) {
+               ret = -ENOMEM;
+               goto error_str;
+       }
+       desc->nr_fields = 0;
+
+       desc->owner = THIS_MODULE;
+       event_notifier->desc = desc;
+
+       return 0;
+
+error_str:
+       kfree(desc);
+       return ret;
+}
+
 static
 int _lttng_kprobes_register(const char *symbol_name,
                           uint64_t offset,
@@ -127,7 +170,7 @@ int _lttng_kprobes_register(const char *symbol_name,
        lttng_kp->kp.addr = (void *) (unsigned long) addr;
 
        /*
-        * Ensure the memory we just allocated don't trigger page faults.
+        * Ensure the memory we just allocated don't event_notifier page faults.
         * Well.. kprobes itself puts the page fault handler on the blacklist,
         * but we can never be too careful.
         */
@@ -173,12 +216,43 @@ error:
 }
 EXPORT_SYMBOL_GPL(lttng_kprobes_register_event);
 
+int lttng_kprobes_register_event_notifier(const char *symbol_name,
+                          uint64_t offset,
+                          uint64_t addr,
+                          struct lttng_event_notifier *event_notifier)
+{
+       int ret;
+       ret = lttng_create_kprobe_event_notifier(symbol_name, event_notifier);
+       if (ret)
+               goto error;
+
+       ret = _lttng_kprobes_register(symbol_name, offset, addr,
+               &event_notifier->u.kprobe, lttng_kprobes_event_notifier_handler_pre);
+       if (ret)
+               goto register_error;
+
+       return 0;
+
+register_error:
+       kfree(event_notifier->desc->name);
+       kfree(event_notifier->desc);
+error:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lttng_kprobes_register_event_notifier);
+
 void lttng_kprobes_unregister_event(struct lttng_event *event)
 {
        unregister_kprobe(&event->u.kprobe.kp);
 }
 EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event);
 
+void lttng_kprobes_unregister_event_notifier(struct lttng_event_notifier *event_notifier)
+{
+       unregister_kprobe(&event_notifier->u.kprobe.kp);
+}
+EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event_notifier);
+
 void lttng_kprobes_destroy_event_private(struct lttng_event *event)
 {
        kfree(event->u.kprobe.symbol_name);
@@ -188,6 +262,14 @@ void lttng_kprobes_destroy_event_private(struct lttng_event *event)
 }
 EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_private);
 
+void lttng_kprobes_destroy_event_notifier_private(struct lttng_event_notifier *event_notifier)
+{
+       kfree(event_notifier->u.kprobe.symbol_name);
+       kfree(event_notifier->desc->name);
+       kfree(event_notifier->desc);
+}
+EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_notifier_private);
+
 MODULE_LICENSE("GPL and additional rights");
 MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
 MODULE_DESCRIPTION("LTTng kprobes probes");
This page took 0.03143 seconds and 4 git commands to generate.