Fix: circular dependency on symbol lttng_id_tracker_lookup
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 22 Feb 2022 16:56:29 +0000 (11:56 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 15 Jul 2024 20:58:48 +0000 (16:58 -0400)
Adding lttng_id_tracker_lookup feature into kprobes, uprobes and
kretprobes introduces a circular dependency between lttng-tracer.ko and
the respective probe modules.

There is no real reason for having the kprobes/uprobes/kretprobes
modules separate from the tracer core, so combine those.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Iea80c8054054b341e1836c8675c04e00424608fc

src/Kbuild
src/lttng-kprobes.c [new file with mode: 0644]
src/lttng-kretprobes.c [new file with mode: 0644]
src/lttng-uprobes.c [new file with mode: 0644]
src/probes/Kbuild
src/probes/lttng-kprobes.c [deleted file]
src/probes/lttng-kretprobes.c [deleted file]
src/probes/lttng-uprobes.c [deleted file]

index a341fd9bd85549eb84d0396ab324e7b202342c94..3fa1807d37bf1a488cef61e016d654edc9bd1c1e 100644 (file)
@@ -140,6 +140,18 @@ ifneq ($(CONFIG_TIME_NS),)
   lttng-tracer-objs += lttng-context-time-ns.o
 endif
 
+ifneq ($(CONFIG_KPROBES),)
+  lttng-tracer-objs += lttng-kprobes.o
+endif
+
+ifneq ($(CONFIG_UPROBES),)
+  lttng-tracer-objs += lttng-uprobes.o
+endif
+
+ifneq ($(CONFIG_KRETPROBES),)
+  lttng-tracer-objs += lttng-kretprobes.o
+endif
+
 obj-$(CONFIG_LTTNG) += lttng-statedump.o
 lttng-statedump-objs := lttng-statedump-impl.o
 
diff --git a/src/lttng-kprobes.c b/src/lttng-kprobes.c
new file mode 100644 (file)
index 0000000..bb6decc
--- /dev/null
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * probes/lttng-kprobes.c
+ *
+ * LTTng kprobes integration module.
+ *
+ * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/slab.h>
+#include <lttng/events.h>
+#include <lttng/events-internal.h>
+#include <ringbuffer/frontend_types.h>
+#include <wrapper/vmalloc.h>
+#include <wrapper/irqflags.h>
+#include <wrapper/rcu.h>
+#include <lttng/tracer.h>
+#include <blacklist/kprobes.h>
+
+static
+int lttng_kprobes_event_handler_pre(struct kprobe *p, struct pt_regs *regs)
+{
+       struct lttng_kernel_event_common_private *event_priv =
+               container_of(p, struct lttng_kernel_event_common_private, u.kprobe.kp);
+       struct lttng_kernel_event_common *event = event_priv->pub;
+       struct lttng_kernel_channel_common *chan_common;
+       struct lttng_kernel_probe_ctx lttng_probe_ctx = {
+               .event = event,
+               .interruptible = !lttng_regs_irqs_disabled(regs),
+       };
+       unsigned long data = (unsigned long) p->addr;
+
+       if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
+               goto end;
+
+       chan_common = lttng_kernel_get_chan_common_from_event_common(event);
+       if (chan_common) {
+               struct lttng_kernel_session *session = chan_common->session;
+               struct lttng_kernel_id_tracker_rcu *lf;
+
+               if (unlikely(!LTTNG_READ_ONCE(session->active)))
+                       goto end;
+               if (unlikely(!LTTNG_READ_ONCE(chan_common->enabled)))
+                       goto end;
+               lf = lttng_rcu_dereference(session->pid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, current->tgid)))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vpid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, task_tgid_vnr(current))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->uid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(&init_user_ns, current_uid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vuid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(current_user_ns(), current_uid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->gid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(&init_user_ns, current_gid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vgid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(current_user_ns(), current_gid()))))
+                       goto end;
+       }
+       switch (event->type) {
+       case LTTNG_KERNEL_EVENT_TYPE_RECORDER:
+       {
+               struct lttng_kernel_event_recorder *event_recorder =
+                       container_of(event, struct lttng_kernel_event_recorder, parent);
+               struct lttng_kernel_channel_buffer *chan = event_recorder->chan;
+               struct lttng_kernel_ring_buffer_ctx ctx;
+               int ret;
+
+               lib_ring_buffer_ctx_init(&ctx, event_recorder, sizeof(data),
+                                        lttng_alignof(data), &lttng_probe_ctx);
+               ret = chan->ops->event_reserve(&ctx);
+               if (ret < 0)
+                       return 0;
+               chan->ops->event_write(&ctx, &data, sizeof(data), lttng_alignof(data));
+               chan->ops->event_commit(&ctx);
+               break;
+       }
+       case LTTNG_KERNEL_EVENT_TYPE_NOTIFIER:
+       {
+               struct lttng_kernel_event_notifier *event_notifier =
+                       container_of(event, struct lttng_kernel_event_notifier, parent);
+               struct lttng_kernel_notification_ctx notif_ctx;
+
+               notif_ctx.eval_capture = LTTNG_READ_ONCE(event_notifier->eval_capture);
+               event_notifier->notification_send(event_notifier, NULL, NULL, &notif_ctx);
+               break;
+       }
+       case LTTNG_KERNEL_EVENT_TYPE_COUNTER:
+       {
+               struct lttng_kernel_event_counter *event_counter =
+                       container_of(event, struct lttng_kernel_event_counter, parent);
+
+               (void) event_counter->chan->ops->event_counter_add(event_counter, 1);
+               break;
+       }
+       default:
+               WARN_ON_ONCE(1);
+       }
+end:
+       return 0;
+}
+
+static const struct lttng_kernel_event_field *event_fields[] = {
+       lttng_kernel_static_event_field("ip",
+               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
+               false, false),
+};
+
+static const struct lttng_kernel_tracepoint_class tp_class = {
+       .nr_fields = ARRAY_SIZE(event_fields),
+       .fields = event_fields,
+};
+
+/*
+ * Create event description
+ */
+static
+int lttng_create_kprobe_event(const char *name, struct lttng_kernel_event_common *event)
+{
+       struct lttng_kernel_event_desc *desc;
+       int ret;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+       desc->tp_class = &tp_class;
+       desc->event_name = kstrdup(name, GFP_KERNEL);
+       if (!desc->event_name) {
+               ret = -ENOMEM;
+               goto error_str;
+       }
+       desc->owner = THIS_MODULE;
+       event->priv->desc = desc;
+
+       return 0;
+
+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 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,
+        * but we can never be too careful.
+        */
+       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;
+}
+
+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 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;
+}
+EXPORT_SYMBOL_GPL(lttng_kprobes_register_event);
+
+void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
+{
+       unregister_kprobe(&event->priv->u.kprobe.kp);
+}
+EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event);
+
+void lttng_kprobes_destroy_event_private(struct lttng_kernel_event_common *event)
+{
+       kfree(event->priv->u.kprobe.symbol_name);
+       kfree(event->priv->desc->event_name);
+       kfree(event->priv->desc);
+}
+EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_private);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
+MODULE_DESCRIPTION("LTTng kprobes probes");
+MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
+       __stringify(LTTNG_MODULES_MINOR_VERSION) "."
+       __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
+       LTTNG_MODULES_EXTRAVERSION);
diff --git a/src/lttng-kretprobes.c b/src/lttng-kretprobes.c
new file mode 100644 (file)
index 0000000..55866a8
--- /dev/null
@@ -0,0 +1,337 @@
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * probes/lttng-kretprobes.c
+ *
+ * LTTng kretprobes integration module.
+ *
+ * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#include <linux/module.h>
+#include <wrapper/kprobes.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+#include <lttng/events.h>
+#include <lttng/events-internal.h>
+#include <ringbuffer/frontend_types.h>
+#include <wrapper/compiler_attributes.h>
+#include <wrapper/vmalloc.h>
+#include <wrapper/irqflags.h>
+#include <wrapper/rcu.h>
+#include <lttng/tracer.h>
+#include <blacklist/kprobes.h>
+
+enum lttng_kretprobe_type {
+       EVENT_ENTRY     = 0,
+       EVENT_EXIT      = 1,
+};
+
+struct lttng_krp {
+       struct kretprobe krp;
+       struct lttng_kernel_event_common *event[2];     /* ENTRY and EXIT */
+       struct kref kref_register;
+       struct kref kref_alloc;
+};
+
+static
+int _lttng_kretprobes_handler(struct kretprobe_instance *krpi,
+                             struct pt_regs *regs,
+                             enum lttng_kretprobe_type type)
+{
+       struct lttng_krp *lttng_krp =
+               container_of(lttng_get_kretprobe(krpi), struct lttng_krp, krp);
+       struct lttng_kernel_event_common *event = lttng_krp->event[type];
+       struct lttng_kernel_channel_common *chan_common;
+       struct lttng_kernel_probe_ctx lttng_probe_ctx = {
+               .event = event,
+               .interruptible = !lttng_regs_irqs_disabled(regs),
+       };
+       struct {
+               unsigned long ip;
+               unsigned long parent_ip;
+       } payload;
+
+       if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
+               goto end;
+
+       chan_common = lttng_kernel_get_chan_common_from_event_common(event);
+       if (chan_common) {
+               struct lttng_kernel_session *session = chan_common->session;
+               struct lttng_kernel_id_tracker_rcu *lf;
+
+               if (unlikely(!LTTNG_READ_ONCE(session->active)))
+                       goto end;
+               if (unlikely(!LTTNG_READ_ONCE(chan_common->enabled)))
+                       goto end;
+               lf = lttng_rcu_dereference(session->pid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, current->tgid)))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vpid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, task_tgid_vnr(current))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->uid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(&init_user_ns, current_uid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vuid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(current_user_ns(), current_uid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->gid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(&init_user_ns, current_gid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vgid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(current_user_ns(), current_gid()))))
+                       goto end;
+       }
+
+       switch (event->type) {
+       case LTTNG_KERNEL_EVENT_TYPE_RECORDER:
+       {
+               struct lttng_kernel_event_recorder *event_recorder =
+                       container_of(event, struct lttng_kernel_event_recorder, parent);
+               struct lttng_kernel_channel_buffer *chan = event_recorder->chan;
+               struct lttng_kernel_ring_buffer_ctx ctx;
+               int ret;
+
+               payload.ip = (unsigned long) lttng_get_kretprobe(krpi)->kp.addr;
+               payload.parent_ip = lttng_get_kretprobe_retaddr(krpi);
+
+               lib_ring_buffer_ctx_init(&ctx, event_recorder, sizeof(payload),
+                                        lttng_alignof(payload), &lttng_probe_ctx);
+               ret = chan->ops->event_reserve(&ctx);
+               if (ret < 0)
+                       return 0;
+               chan->ops->event_write(&ctx, &payload, sizeof(payload), lttng_alignof(payload));
+               chan->ops->event_commit(&ctx);
+               break;
+       }
+       case LTTNG_KERNEL_EVENT_TYPE_COUNTER:
+       {
+               struct lttng_kernel_event_counter *event_counter =
+                       container_of(event, struct lttng_kernel_event_counter, parent);
+
+               (void) event_counter->chan->ops->event_counter_add(event_counter, 1);
+               break;
+       }
+       case LTTNG_KERNEL_EVENT_TYPE_NOTIFIER:
+               lttng_fallthrough;
+       default:
+               WARN_ON_ONCE(1);
+       }
+end:
+       return 0;
+}
+
+static
+int lttng_kretprobes_handler_entry(struct kretprobe_instance *krpi,
+                                  struct pt_regs *regs)
+{
+       return _lttng_kretprobes_handler(krpi, regs, EVENT_ENTRY);
+}
+
+static
+int lttng_kretprobes_handler_exit(struct kretprobe_instance *krpi,
+                                 struct pt_regs *regs)
+{
+       return _lttng_kretprobes_handler(krpi, regs, EVENT_EXIT);
+}
+
+static const struct lttng_kernel_event_field *event_fields[] = {
+       lttng_kernel_static_event_field("ip",
+               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
+               false, false),
+       lttng_kernel_static_event_field("parent_ip",
+               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
+               false, false),
+};
+
+static const struct lttng_kernel_tracepoint_class tp_class = {
+       .nr_fields = ARRAY_SIZE(event_fields),
+       .fields = event_fields,
+};
+
+/*
+ * 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 *desc;
+       char *alloc_name;
+       size_t name_len;
+       const char *suffix = NULL;
+       int ret;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+       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;
+               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;
+
+error_str:
+       kfree(desc);
+       return ret;
+}
+
+int lttng_kretprobes_register(const char *name,
+                          const char *symbol_name,
+                          uint64_t offset,
+                          uint64_t addr,
+                          struct lttng_kernel_event_common *event_entry,
+                          struct lttng_kernel_event_common *event_exit)
+{
+       int ret;
+       struct lttng_krp *lttng_krp;
+
+       /* Kprobes expects a NULL symbol name if unused */
+       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;
+       lttng_krp->krp.entry_handler = lttng_kretprobes_handler_entry;
+       lttng_krp->krp.handler = lttng_kretprobes_handler_exit;
+       if (symbol_name) {
+               char *alloc_symbol;
+
+               alloc_symbol = kstrdup(symbol_name, GFP_KERNEL);
+               if (!alloc_symbol) {
+                       ret = -ENOMEM;
+                       goto name_error;
+               }
+               lttng_krp->krp.kp.symbol_name = alloc_symbol;
+               event_entry->priv->u.kretprobe.symbol_name = alloc_symbol;
+               event_exit->priv->u.kretprobe.symbol_name = alloc_symbol;
+       }
+       lttng_krp->krp.kp.offset = offset;
+       lttng_krp->krp.kp.addr = (void *) (unsigned long) addr;
+
+       /* Allow probe handler to find event structures */
+       lttng_krp->event[EVENT_ENTRY] = event_entry;
+       lttng_krp->event[EVENT_EXIT] = event_exit;
+       event_entry->priv->u.kretprobe.lttng_krp = lttng_krp;
+       event_exit->priv->u.kretprobe.lttng_krp = lttng_krp;
+
+       /*
+        * Both events must be unregistered before the kretprobe is
+        * unregistered. Same for memory allocation.
+        */
+       kref_init(&lttng_krp->kref_alloc);
+       kref_get(&lttng_krp->kref_alloc);       /* inc refcount to 2, no overflow. */
+       kref_init(&lttng_krp->kref_register);
+       kref_get(&lttng_krp->kref_register);    /* inc refcount to 2, no overflow. */
+
+       /*
+        * Ensure the memory we just allocated don't trigger page faults.
+        * Well.. kprobes itself puts the page fault handler on the blacklist,
+        * but we can never be too careful.
+        */
+       wrapper_vmalloc_sync_mappings();
+
+       ret = register_kretprobe(&lttng_krp->krp);
+       if (ret)
+               goto register_error;
+       return 0;
+
+register_error:
+       kfree(lttng_krp->krp.kp.symbol_name);
+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;
+}
+EXPORT_SYMBOL_GPL(lttng_kretprobes_register);
+
+static
+void _lttng_kretprobes_unregister_release(struct kref *kref)
+{
+       struct lttng_krp *lttng_krp =
+               container_of(kref, struct lttng_krp, kref_register);
+       unregister_kretprobe(&lttng_krp->krp);
+}
+
+void lttng_kretprobes_unregister(struct lttng_kernel_event_common *event)
+{
+       kref_put(&event->priv->u.kretprobe.lttng_krp->kref_register,
+               _lttng_kretprobes_unregister_release);
+}
+EXPORT_SYMBOL_GPL(lttng_kretprobes_unregister);
+
+static
+void _lttng_kretprobes_release(struct kref *kref)
+{
+       struct lttng_krp *lttng_krp =
+               container_of(kref, struct lttng_krp, kref_alloc);
+       kfree(lttng_krp->krp.kp.symbol_name);
+}
+
+void lttng_kretprobes_destroy_private(struct lttng_kernel_event_common *event)
+{
+       kfree(event->priv->desc->event_name);
+       kfree(event->priv->desc);
+       kref_put(&event->priv->u.kretprobe.lttng_krp->kref_alloc,
+               _lttng_kretprobes_release);
+}
+EXPORT_SYMBOL_GPL(lttng_kretprobes_destroy_private);
+
+int lttng_kretprobes_event_enable_state(struct lttng_kernel_event_common *event,
+               int enable)
+{
+       struct lttng_kernel_event_common *event_exit;
+       struct lttng_krp *lttng_krp;
+
+       if (event->priv->instrumentation != LTTNG_KERNEL_ABI_KRETPROBE) {
+               return -EINVAL;
+       }
+       if (event->enabled == enable) {
+               return -EBUSY;
+       }
+       lttng_krp = event->priv->u.kretprobe.lttng_krp;
+       event_exit = lttng_krp->event[EVENT_EXIT];
+       WRITE_ONCE(event->enabled, enable);
+       WRITE_ONCE(event_exit->enabled, enable);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lttng_kretprobes_event_enable_state);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
+MODULE_DESCRIPTION("LTTng kretprobes probes");
+MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
+       __stringify(LTTNG_MODULES_MINOR_VERSION) "."
+       __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
+       LTTNG_MODULES_EXTRAVERSION);
diff --git a/src/lttng-uprobes.c b/src/lttng-uprobes.c
new file mode 100644 (file)
index 0000000..bf4305f
--- /dev/null
@@ -0,0 +1,333 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR LGPL-2.1-only)
+ *
+ * probes/lttng-uprobes.c
+ *
+ * LTTng uprobes integration module.
+ *
+ * Copyright (C) 2013 Yannick Brosseau <yannick.brosseau@gmail.com>
+ * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ */
+
+#include <wrapper/fdtable.h>
+#include <linux/file.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/uprobes.h>
+
+#include <lttng/events.h>
+#include <lttng/events-internal.h>
+#include <lttng/tracer.h>
+#include <wrapper/irqflags.h>
+#include <wrapper/rcu.h>
+#include <ringbuffer/frontend_types.h>
+#include <wrapper/vmalloc.h>
+
+static
+int lttng_uprobes_event_handler_pre(struct uprobe_consumer *uc, struct pt_regs *regs)
+{
+       struct lttng_uprobe_handler *uprobe_handler =
+               container_of(uc, struct lttng_uprobe_handler, up_consumer);
+       struct lttng_kernel_event_common *event = uprobe_handler->event;
+       struct lttng_kernel_channel_common *chan_common;
+       struct lttng_kernel_probe_ctx lttng_probe_ctx = {
+               .event = event,
+               .interruptible = !lttng_regs_irqs_disabled(regs),
+       };
+       struct {
+               unsigned long ip;
+       } payload;
+
+       if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
+               goto end;
+
+       chan_common = lttng_kernel_get_chan_common_from_event_common(event);
+       if (chan_common) {
+               struct lttng_kernel_session *session = chan_common->session;
+               struct lttng_kernel_id_tracker_rcu *lf;
+
+               if (unlikely(!LTTNG_READ_ONCE(session->active)))
+                       goto end;
+               if (unlikely(!LTTNG_READ_ONCE(chan_common->enabled)))
+                       goto end;
+               lf = lttng_rcu_dereference(session->pid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, current->tgid)))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vpid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, task_tgid_vnr(current))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->uid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(&init_user_ns, current_uid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vuid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(current_user_ns(), current_uid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->gid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(&init_user_ns, current_gid()))))
+                       goto end;
+               lf = lttng_rcu_dereference(session->vgid_tracker.p);
+               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(current_user_ns(), current_gid()))))
+                       goto end;
+       }
+       switch (event->type) {
+       case LTTNG_KERNEL_EVENT_TYPE_RECORDER:
+       {
+               struct lttng_kernel_event_recorder *event_recorder =
+                       container_of(event, struct lttng_kernel_event_recorder, parent);
+               struct lttng_kernel_channel_buffer *chan = event_recorder->chan;
+               struct lttng_kernel_ring_buffer_ctx ctx;
+               int ret;
+
+               lib_ring_buffer_ctx_init(&ctx, event_recorder,
+                       sizeof(payload), lttng_alignof(payload), &lttng_probe_ctx);
+
+               ret = chan->ops->event_reserve(&ctx);
+               if (ret < 0)
+                       return 0;
+
+               /* Event payload. */
+               payload.ip = (unsigned long)instruction_pointer(regs);
+
+               chan->ops->event_write(&ctx, &payload, sizeof(payload), lttng_alignof(payload));
+               chan->ops->event_commit(&ctx);
+               break;
+       }
+       case LTTNG_KERNEL_EVENT_TYPE_NOTIFIER:
+       {
+               struct lttng_kernel_event_notifier *event_notifier =
+                       container_of(event, struct lttng_kernel_event_notifier, parent);
+               struct lttng_kernel_notification_ctx notif_ctx;
+
+               notif_ctx.eval_capture = LTTNG_READ_ONCE(event_notifier->eval_capture);
+               event_notifier->notification_send(event_notifier, NULL, NULL, &notif_ctx);
+               break;
+       }
+       case LTTNG_KERNEL_EVENT_TYPE_COUNTER:
+       {
+               struct lttng_kernel_event_counter *event_counter =
+                       container_of(event, struct lttng_kernel_event_counter, parent);
+
+               /* uprobes is invoked with preemption enabled. */
+               rcu_read_lock_sched_notrace();
+               (void) event_counter->chan->ops->event_counter_add(event_counter, 1);
+               rcu_read_unlock_sched_notrace();
+               break;
+       }
+       default:
+               WARN_ON_ONCE(1);
+       }
+end:
+       return 0;
+}
+
+static const struct lttng_kernel_event_field *event_fields[] = {
+       lttng_kernel_static_event_field("ip",
+               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
+               false, false),
+};
+
+static const struct lttng_kernel_tracepoint_class tp_class = {
+       .nr_fields = ARRAY_SIZE(event_fields),
+       .fields = event_fields,
+};
+
+/*
+ * Create event description.
+ */
+static
+int lttng_create_uprobe_event(const char *name, struct lttng_kernel_event_common *event)
+{
+       struct lttng_kernel_event_desc *desc;
+       int ret;
+
+       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+       desc->tp_class = &tp_class;
+       desc->event_name = kstrdup(name, GFP_KERNEL);
+       if (!desc->event_name) {
+               ret = -ENOMEM;
+               goto error_str;
+       }
+       desc->owner = THIS_MODULE;
+       event->priv->desc = desc;
+
+       return 0;
+
+error_str:
+       kfree(desc);
+       return ret;
+}
+
+/*
+ * Returns the inode struct from the current task and an fd. The inode is
+ * grabbed by this function and must be put once we are done with it using
+ * iput().
+ */
+static struct inode *get_inode_from_fd(int fd)
+{
+       struct file *file;
+       struct inode *inode;
+
+       rcu_read_lock();
+       /*
+        * Returns the file backing the given fd. Needs to be done inside an RCU
+        * critical section.
+        */
+       file = lttng_lookup_fdget_rcu(fd);
+       if (file == NULL) {
+               printk(KERN_WARNING "LTTng: Cannot access file backing the fd(%d)\n", fd);
+               inode = NULL;
+               goto error;
+       }
+
+       /* Grab a reference on the inode. */
+       inode = igrab(file->f_path.dentry->d_inode);
+       if (inode == NULL)
+               printk(KERN_WARNING "LTTng: Cannot grab a reference on the inode.\n");
+
+error:
+       rcu_read_unlock();
+       if (file)
+               fput(file);
+       return inode;
+}
+
+
+static
+int lttng_uprobes_add_callsite(struct lttng_uprobe *uprobe,
+       struct lttng_kernel_abi_event_callsite __user *callsite,
+       int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs),
+       void *priv_data)
+{
+       int ret = 0;
+       struct lttng_uprobe_handler *uprobe_handler;
+
+       if (!priv_data) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       uprobe_handler = kzalloc(sizeof(struct lttng_uprobe_handler), GFP_KERNEL);
+       if (!uprobe_handler) {
+               printk(KERN_WARNING "LTTng: Error allocating uprobe_handler");
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       /* Ensure the memory we just allocated don't notify page faults. */
+       wrapper_vmalloc_sync_mappings();
+
+       uprobe_handler->event = priv_data;
+       uprobe_handler->up_consumer.handler = handler;
+
+       ret = copy_from_user(&uprobe_handler->offset, &callsite->u.uprobe.offset, sizeof(uint64_t));
+       if (ret) {
+               goto register_error;
+       }
+
+       ret = uprobe_register(uprobe->inode,
+                     uprobe_handler->offset, &uprobe_handler->up_consumer);
+       if (ret) {
+               printk(KERN_WARNING "LTTng: Error registering probe on inode %lu "
+                      "and offset 0x%llx\n", uprobe->inode->i_ino,
+                      uprobe_handler->offset);
+               ret = -1;
+               goto register_error;
+       }
+
+       list_add(&uprobe_handler->node, &uprobe->head);
+
+       return ret;
+
+register_error:
+       kfree(uprobe_handler);
+end:
+       return ret;
+}
+
+int lttng_uprobes_event_add_callsite(struct lttng_kernel_event_common *event,
+       struct lttng_kernel_abi_event_callsite __user *callsite)
+{
+       return lttng_uprobes_add_callsite(&event->priv->u.uprobe, callsite,
+               lttng_uprobes_event_handler_pre, event);
+}
+EXPORT_SYMBOL_GPL(lttng_uprobes_event_add_callsite);
+
+static
+int lttng_uprobes_register(struct lttng_uprobe *uprobe, int fd)
+{
+       int ret = 0;
+       struct inode *inode;
+
+       inode = get_inode_from_fd(fd);
+       if (!inode) {
+               printk(KERN_WARNING "LTTng: Cannot get inode from fd\n");
+               ret = -EBADF;
+               goto inode_error;
+       }
+       uprobe->inode = inode;
+       INIT_LIST_HEAD(&uprobe->head);
+
+inode_error:
+       return ret;
+}
+
+int lttng_uprobes_register_event(const char *name, int fd, struct lttng_kernel_event_common *event)
+{
+       int ret = 0;
+
+       ret = lttng_create_uprobe_event(name, event);
+       if (ret)
+               goto error;
+
+       ret = lttng_uprobes_register(&event->priv->u.uprobe, fd);
+       if (ret)
+               goto register_error;
+
+       return 0;
+
+register_error:
+       kfree(event->priv->desc->event_name);
+       kfree(event->priv->desc);
+error:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(lttng_uprobes_register_event);
+
+static
+void lttng_uprobes_unregister(struct inode *inode, struct list_head *head)
+{
+       struct lttng_uprobe_handler *iter, *tmp;
+
+       /*
+        * Iterate over the list of handler, remove each handler from the list
+        * and free the struct.
+        */
+       list_for_each_entry_safe(iter, tmp, head, node) {
+               uprobe_unregister(inode, iter->offset, &iter->up_consumer);
+               list_del(&iter->node);
+               kfree(iter);
+       }
+}
+
+void lttng_uprobes_unregister_event(struct lttng_kernel_event_common *event)
+{
+       lttng_uprobes_unregister(event->priv->u.uprobe.inode, &event->priv->u.uprobe.head);
+}
+EXPORT_SYMBOL_GPL(lttng_uprobes_unregister_event);
+
+void lttng_uprobes_destroy_event_private(struct lttng_kernel_event_common *event)
+{
+       iput(event->priv->u.uprobe.inode);
+       kfree(event->priv->desc->event_name);
+       kfree(event->priv->desc);
+}
+EXPORT_SYMBOL_GPL(lttng_uprobes_destroy_event_private);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Yannick Brosseau");
+MODULE_DESCRIPTION("Linux Trace Toolkit Uprobes Support");
index c4273e01643ae575b47e301f48b049e6838a561a..f9677678b3fa59cdde2662050869bca452f4a2d7 100644 (file)
@@ -236,18 +236,6 @@ else
   endif
 endif # CONFIG_KALLSYMS_ALL
 
-ifneq ($(CONFIG_KPROBES),)
-  obj-$(CONFIG_LTTNG) += lttng-kprobes.o
-endif # CONFIG_KPROBES
-
-ifneq ($(CONFIG_UPROBES),)
-  obj-$(CONFIG_LTTNG) += lttng-uprobes.o
-endif # CONFIG_UPROBES
-
-ifneq ($(CONFIG_KRETPROBES),)
-  obj-$(CONFIG_LTTNG) += lttng-kretprobes.o
-endif # CONFIG_KRETPROBES
-
 ifneq ($(CONFIG_PREEMPTIRQ_EVENTS),)
   obj-$(CONFIG_LTTNG) += lttng-probe-preemptirq.o
 endif # CONFIG_PREEMPTIRQ_EVENTS
diff --git a/src/probes/lttng-kprobes.c b/src/probes/lttng-kprobes.c
deleted file mode 100644 (file)
index bb6decc..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
- *
- * probes/lttng-kprobes.c
- *
- * LTTng kprobes integration module.
- *
- * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#include <linux/module.h>
-#include <linux/kprobes.h>
-#include <linux/slab.h>
-#include <lttng/events.h>
-#include <lttng/events-internal.h>
-#include <ringbuffer/frontend_types.h>
-#include <wrapper/vmalloc.h>
-#include <wrapper/irqflags.h>
-#include <wrapper/rcu.h>
-#include <lttng/tracer.h>
-#include <blacklist/kprobes.h>
-
-static
-int lttng_kprobes_event_handler_pre(struct kprobe *p, struct pt_regs *regs)
-{
-       struct lttng_kernel_event_common_private *event_priv =
-               container_of(p, struct lttng_kernel_event_common_private, u.kprobe.kp);
-       struct lttng_kernel_event_common *event = event_priv->pub;
-       struct lttng_kernel_channel_common *chan_common;
-       struct lttng_kernel_probe_ctx lttng_probe_ctx = {
-               .event = event,
-               .interruptible = !lttng_regs_irqs_disabled(regs),
-       };
-       unsigned long data = (unsigned long) p->addr;
-
-       if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
-               goto end;
-
-       chan_common = lttng_kernel_get_chan_common_from_event_common(event);
-       if (chan_common) {
-               struct lttng_kernel_session *session = chan_common->session;
-               struct lttng_kernel_id_tracker_rcu *lf;
-
-               if (unlikely(!LTTNG_READ_ONCE(session->active)))
-                       goto end;
-               if (unlikely(!LTTNG_READ_ONCE(chan_common->enabled)))
-                       goto end;
-               lf = lttng_rcu_dereference(session->pid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, current->tgid)))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vpid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, task_tgid_vnr(current))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->uid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(&init_user_ns, current_uid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vuid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(current_user_ns(), current_uid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->gid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(&init_user_ns, current_gid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vgid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(current_user_ns(), current_gid()))))
-                       goto end;
-       }
-       switch (event->type) {
-       case LTTNG_KERNEL_EVENT_TYPE_RECORDER:
-       {
-               struct lttng_kernel_event_recorder *event_recorder =
-                       container_of(event, struct lttng_kernel_event_recorder, parent);
-               struct lttng_kernel_channel_buffer *chan = event_recorder->chan;
-               struct lttng_kernel_ring_buffer_ctx ctx;
-               int ret;
-
-               lib_ring_buffer_ctx_init(&ctx, event_recorder, sizeof(data),
-                                        lttng_alignof(data), &lttng_probe_ctx);
-               ret = chan->ops->event_reserve(&ctx);
-               if (ret < 0)
-                       return 0;
-               chan->ops->event_write(&ctx, &data, sizeof(data), lttng_alignof(data));
-               chan->ops->event_commit(&ctx);
-               break;
-       }
-       case LTTNG_KERNEL_EVENT_TYPE_NOTIFIER:
-       {
-               struct lttng_kernel_event_notifier *event_notifier =
-                       container_of(event, struct lttng_kernel_event_notifier, parent);
-               struct lttng_kernel_notification_ctx notif_ctx;
-
-               notif_ctx.eval_capture = LTTNG_READ_ONCE(event_notifier->eval_capture);
-               event_notifier->notification_send(event_notifier, NULL, NULL, &notif_ctx);
-               break;
-       }
-       case LTTNG_KERNEL_EVENT_TYPE_COUNTER:
-       {
-               struct lttng_kernel_event_counter *event_counter =
-                       container_of(event, struct lttng_kernel_event_counter, parent);
-
-               (void) event_counter->chan->ops->event_counter_add(event_counter, 1);
-               break;
-       }
-       default:
-               WARN_ON_ONCE(1);
-       }
-end:
-       return 0;
-}
-
-static const struct lttng_kernel_event_field *event_fields[] = {
-       lttng_kernel_static_event_field("ip",
-               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
-               false, false),
-};
-
-static const struct lttng_kernel_tracepoint_class tp_class = {
-       .nr_fields = ARRAY_SIZE(event_fields),
-       .fields = event_fields,
-};
-
-/*
- * Create event description
- */
-static
-int lttng_create_kprobe_event(const char *name, struct lttng_kernel_event_common *event)
-{
-       struct lttng_kernel_event_desc *desc;
-       int ret;
-
-       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-       desc->tp_class = &tp_class;
-       desc->event_name = kstrdup(name, GFP_KERNEL);
-       if (!desc->event_name) {
-               ret = -ENOMEM;
-               goto error_str;
-       }
-       desc->owner = THIS_MODULE;
-       event->priv->desc = desc;
-
-       return 0;
-
-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 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,
-        * but we can never be too careful.
-        */
-       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;
-}
-
-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 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;
-}
-EXPORT_SYMBOL_GPL(lttng_kprobes_register_event);
-
-void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
-{
-       unregister_kprobe(&event->priv->u.kprobe.kp);
-}
-EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event);
-
-void lttng_kprobes_destroy_event_private(struct lttng_kernel_event_common *event)
-{
-       kfree(event->priv->u.kprobe.symbol_name);
-       kfree(event->priv->desc->event_name);
-       kfree(event->priv->desc);
-}
-EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_private);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
-MODULE_DESCRIPTION("LTTng kprobes probes");
-MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
-       __stringify(LTTNG_MODULES_MINOR_VERSION) "."
-       __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
-       LTTNG_MODULES_EXTRAVERSION);
diff --git a/src/probes/lttng-kretprobes.c b/src/probes/lttng-kretprobes.c
deleted file mode 100644 (file)
index 55866a8..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
- *
- * probes/lttng-kretprobes.c
- *
- * LTTng kretprobes integration module.
- *
- * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#include <linux/module.h>
-#include <wrapper/kprobes.h>
-#include <linux/slab.h>
-#include <linux/kref.h>
-#include <lttng/events.h>
-#include <lttng/events-internal.h>
-#include <ringbuffer/frontend_types.h>
-#include <wrapper/compiler_attributes.h>
-#include <wrapper/vmalloc.h>
-#include <wrapper/irqflags.h>
-#include <wrapper/rcu.h>
-#include <lttng/tracer.h>
-#include <blacklist/kprobes.h>
-
-enum lttng_kretprobe_type {
-       EVENT_ENTRY     = 0,
-       EVENT_EXIT      = 1,
-};
-
-struct lttng_krp {
-       struct kretprobe krp;
-       struct lttng_kernel_event_common *event[2];     /* ENTRY and EXIT */
-       struct kref kref_register;
-       struct kref kref_alloc;
-};
-
-static
-int _lttng_kretprobes_handler(struct kretprobe_instance *krpi,
-                             struct pt_regs *regs,
-                             enum lttng_kretprobe_type type)
-{
-       struct lttng_krp *lttng_krp =
-               container_of(lttng_get_kretprobe(krpi), struct lttng_krp, krp);
-       struct lttng_kernel_event_common *event = lttng_krp->event[type];
-       struct lttng_kernel_channel_common *chan_common;
-       struct lttng_kernel_probe_ctx lttng_probe_ctx = {
-               .event = event,
-               .interruptible = !lttng_regs_irqs_disabled(regs),
-       };
-       struct {
-               unsigned long ip;
-               unsigned long parent_ip;
-       } payload;
-
-       if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
-               goto end;
-
-       chan_common = lttng_kernel_get_chan_common_from_event_common(event);
-       if (chan_common) {
-               struct lttng_kernel_session *session = chan_common->session;
-               struct lttng_kernel_id_tracker_rcu *lf;
-
-               if (unlikely(!LTTNG_READ_ONCE(session->active)))
-                       goto end;
-               if (unlikely(!LTTNG_READ_ONCE(chan_common->enabled)))
-                       goto end;
-               lf = lttng_rcu_dereference(session->pid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, current->tgid)))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vpid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, task_tgid_vnr(current))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->uid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(&init_user_ns, current_uid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vuid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(current_user_ns(), current_uid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->gid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(&init_user_ns, current_gid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vgid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(current_user_ns(), current_gid()))))
-                       goto end;
-       }
-
-       switch (event->type) {
-       case LTTNG_KERNEL_EVENT_TYPE_RECORDER:
-       {
-               struct lttng_kernel_event_recorder *event_recorder =
-                       container_of(event, struct lttng_kernel_event_recorder, parent);
-               struct lttng_kernel_channel_buffer *chan = event_recorder->chan;
-               struct lttng_kernel_ring_buffer_ctx ctx;
-               int ret;
-
-               payload.ip = (unsigned long) lttng_get_kretprobe(krpi)->kp.addr;
-               payload.parent_ip = lttng_get_kretprobe_retaddr(krpi);
-
-               lib_ring_buffer_ctx_init(&ctx, event_recorder, sizeof(payload),
-                                        lttng_alignof(payload), &lttng_probe_ctx);
-               ret = chan->ops->event_reserve(&ctx);
-               if (ret < 0)
-                       return 0;
-               chan->ops->event_write(&ctx, &payload, sizeof(payload), lttng_alignof(payload));
-               chan->ops->event_commit(&ctx);
-               break;
-       }
-       case LTTNG_KERNEL_EVENT_TYPE_COUNTER:
-       {
-               struct lttng_kernel_event_counter *event_counter =
-                       container_of(event, struct lttng_kernel_event_counter, parent);
-
-               (void) event_counter->chan->ops->event_counter_add(event_counter, 1);
-               break;
-       }
-       case LTTNG_KERNEL_EVENT_TYPE_NOTIFIER:
-               lttng_fallthrough;
-       default:
-               WARN_ON_ONCE(1);
-       }
-end:
-       return 0;
-}
-
-static
-int lttng_kretprobes_handler_entry(struct kretprobe_instance *krpi,
-                                  struct pt_regs *regs)
-{
-       return _lttng_kretprobes_handler(krpi, regs, EVENT_ENTRY);
-}
-
-static
-int lttng_kretprobes_handler_exit(struct kretprobe_instance *krpi,
-                                 struct pt_regs *regs)
-{
-       return _lttng_kretprobes_handler(krpi, regs, EVENT_EXIT);
-}
-
-static const struct lttng_kernel_event_field *event_fields[] = {
-       lttng_kernel_static_event_field("ip",
-               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
-               false, false),
-       lttng_kernel_static_event_field("parent_ip",
-               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
-               false, false),
-};
-
-static const struct lttng_kernel_tracepoint_class tp_class = {
-       .nr_fields = ARRAY_SIZE(event_fields),
-       .fields = event_fields,
-};
-
-/*
- * 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 *desc;
-       char *alloc_name;
-       size_t name_len;
-       const char *suffix = NULL;
-       int ret;
-
-       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-       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;
-               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;
-
-error_str:
-       kfree(desc);
-       return ret;
-}
-
-int lttng_kretprobes_register(const char *name,
-                          const char *symbol_name,
-                          uint64_t offset,
-                          uint64_t addr,
-                          struct lttng_kernel_event_common *event_entry,
-                          struct lttng_kernel_event_common *event_exit)
-{
-       int ret;
-       struct lttng_krp *lttng_krp;
-
-       /* Kprobes expects a NULL symbol name if unused */
-       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;
-       lttng_krp->krp.entry_handler = lttng_kretprobes_handler_entry;
-       lttng_krp->krp.handler = lttng_kretprobes_handler_exit;
-       if (symbol_name) {
-               char *alloc_symbol;
-
-               alloc_symbol = kstrdup(symbol_name, GFP_KERNEL);
-               if (!alloc_symbol) {
-                       ret = -ENOMEM;
-                       goto name_error;
-               }
-               lttng_krp->krp.kp.symbol_name = alloc_symbol;
-               event_entry->priv->u.kretprobe.symbol_name = alloc_symbol;
-               event_exit->priv->u.kretprobe.symbol_name = alloc_symbol;
-       }
-       lttng_krp->krp.kp.offset = offset;
-       lttng_krp->krp.kp.addr = (void *) (unsigned long) addr;
-
-       /* Allow probe handler to find event structures */
-       lttng_krp->event[EVENT_ENTRY] = event_entry;
-       lttng_krp->event[EVENT_EXIT] = event_exit;
-       event_entry->priv->u.kretprobe.lttng_krp = lttng_krp;
-       event_exit->priv->u.kretprobe.lttng_krp = lttng_krp;
-
-       /*
-        * Both events must be unregistered before the kretprobe is
-        * unregistered. Same for memory allocation.
-        */
-       kref_init(&lttng_krp->kref_alloc);
-       kref_get(&lttng_krp->kref_alloc);       /* inc refcount to 2, no overflow. */
-       kref_init(&lttng_krp->kref_register);
-       kref_get(&lttng_krp->kref_register);    /* inc refcount to 2, no overflow. */
-
-       /*
-        * Ensure the memory we just allocated don't trigger page faults.
-        * Well.. kprobes itself puts the page fault handler on the blacklist,
-        * but we can never be too careful.
-        */
-       wrapper_vmalloc_sync_mappings();
-
-       ret = register_kretprobe(&lttng_krp->krp);
-       if (ret)
-               goto register_error;
-       return 0;
-
-register_error:
-       kfree(lttng_krp->krp.kp.symbol_name);
-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;
-}
-EXPORT_SYMBOL_GPL(lttng_kretprobes_register);
-
-static
-void _lttng_kretprobes_unregister_release(struct kref *kref)
-{
-       struct lttng_krp *lttng_krp =
-               container_of(kref, struct lttng_krp, kref_register);
-       unregister_kretprobe(&lttng_krp->krp);
-}
-
-void lttng_kretprobes_unregister(struct lttng_kernel_event_common *event)
-{
-       kref_put(&event->priv->u.kretprobe.lttng_krp->kref_register,
-               _lttng_kretprobes_unregister_release);
-}
-EXPORT_SYMBOL_GPL(lttng_kretprobes_unregister);
-
-static
-void _lttng_kretprobes_release(struct kref *kref)
-{
-       struct lttng_krp *lttng_krp =
-               container_of(kref, struct lttng_krp, kref_alloc);
-       kfree(lttng_krp->krp.kp.symbol_name);
-}
-
-void lttng_kretprobes_destroy_private(struct lttng_kernel_event_common *event)
-{
-       kfree(event->priv->desc->event_name);
-       kfree(event->priv->desc);
-       kref_put(&event->priv->u.kretprobe.lttng_krp->kref_alloc,
-               _lttng_kretprobes_release);
-}
-EXPORT_SYMBOL_GPL(lttng_kretprobes_destroy_private);
-
-int lttng_kretprobes_event_enable_state(struct lttng_kernel_event_common *event,
-               int enable)
-{
-       struct lttng_kernel_event_common *event_exit;
-       struct lttng_krp *lttng_krp;
-
-       if (event->priv->instrumentation != LTTNG_KERNEL_ABI_KRETPROBE) {
-               return -EINVAL;
-       }
-       if (event->enabled == enable) {
-               return -EBUSY;
-       }
-       lttng_krp = event->priv->u.kretprobe.lttng_krp;
-       event_exit = lttng_krp->event[EVENT_EXIT];
-       WRITE_ONCE(event->enabled, enable);
-       WRITE_ONCE(event_exit->enabled, enable);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lttng_kretprobes_event_enable_state);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
-MODULE_DESCRIPTION("LTTng kretprobes probes");
-MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
-       __stringify(LTTNG_MODULES_MINOR_VERSION) "."
-       __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
-       LTTNG_MODULES_EXTRAVERSION);
diff --git a/src/probes/lttng-uprobes.c b/src/probes/lttng-uprobes.c
deleted file mode 100644 (file)
index bf4305f..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0-only OR LGPL-2.1-only)
- *
- * probes/lttng-uprobes.c
- *
- * LTTng uprobes integration module.
- *
- * Copyright (C) 2013 Yannick Brosseau <yannick.brosseau@gmail.com>
- * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- */
-
-#include <wrapper/fdtable.h>
-#include <linux/file.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/namei.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/uprobes.h>
-
-#include <lttng/events.h>
-#include <lttng/events-internal.h>
-#include <lttng/tracer.h>
-#include <wrapper/irqflags.h>
-#include <wrapper/rcu.h>
-#include <ringbuffer/frontend_types.h>
-#include <wrapper/vmalloc.h>
-
-static
-int lttng_uprobes_event_handler_pre(struct uprobe_consumer *uc, struct pt_regs *regs)
-{
-       struct lttng_uprobe_handler *uprobe_handler =
-               container_of(uc, struct lttng_uprobe_handler, up_consumer);
-       struct lttng_kernel_event_common *event = uprobe_handler->event;
-       struct lttng_kernel_channel_common *chan_common;
-       struct lttng_kernel_probe_ctx lttng_probe_ctx = {
-               .event = event,
-               .interruptible = !lttng_regs_irqs_disabled(regs),
-       };
-       struct {
-               unsigned long ip;
-       } payload;
-
-       if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
-               goto end;
-
-       chan_common = lttng_kernel_get_chan_common_from_event_common(event);
-       if (chan_common) {
-               struct lttng_kernel_session *session = chan_common->session;
-               struct lttng_kernel_id_tracker_rcu *lf;
-
-               if (unlikely(!LTTNG_READ_ONCE(session->active)))
-                       goto end;
-               if (unlikely(!LTTNG_READ_ONCE(chan_common->enabled)))
-                       goto end;
-               lf = lttng_rcu_dereference(session->pid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, current->tgid)))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vpid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, task_tgid_vnr(current))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->uid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(&init_user_ns, current_uid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vuid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kuid_munged(current_user_ns(), current_uid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->gid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(&init_user_ns, current_gid()))))
-                       goto end;
-               lf = lttng_rcu_dereference(session->vgid_tracker.p);
-               if (lf && likely(!lttng_id_tracker_lookup(lf, from_kgid_munged(current_user_ns(), current_gid()))))
-                       goto end;
-       }
-       switch (event->type) {
-       case LTTNG_KERNEL_EVENT_TYPE_RECORDER:
-       {
-               struct lttng_kernel_event_recorder *event_recorder =
-                       container_of(event, struct lttng_kernel_event_recorder, parent);
-               struct lttng_kernel_channel_buffer *chan = event_recorder->chan;
-               struct lttng_kernel_ring_buffer_ctx ctx;
-               int ret;
-
-               lib_ring_buffer_ctx_init(&ctx, event_recorder,
-                       sizeof(payload), lttng_alignof(payload), &lttng_probe_ctx);
-
-               ret = chan->ops->event_reserve(&ctx);
-               if (ret < 0)
-                       return 0;
-
-               /* Event payload. */
-               payload.ip = (unsigned long)instruction_pointer(regs);
-
-               chan->ops->event_write(&ctx, &payload, sizeof(payload), lttng_alignof(payload));
-               chan->ops->event_commit(&ctx);
-               break;
-       }
-       case LTTNG_KERNEL_EVENT_TYPE_NOTIFIER:
-       {
-               struct lttng_kernel_event_notifier *event_notifier =
-                       container_of(event, struct lttng_kernel_event_notifier, parent);
-               struct lttng_kernel_notification_ctx notif_ctx;
-
-               notif_ctx.eval_capture = LTTNG_READ_ONCE(event_notifier->eval_capture);
-               event_notifier->notification_send(event_notifier, NULL, NULL, &notif_ctx);
-               break;
-       }
-       case LTTNG_KERNEL_EVENT_TYPE_COUNTER:
-       {
-               struct lttng_kernel_event_counter *event_counter =
-                       container_of(event, struct lttng_kernel_event_counter, parent);
-
-               /* uprobes is invoked with preemption enabled. */
-               rcu_read_lock_sched_notrace();
-               (void) event_counter->chan->ops->event_counter_add(event_counter, 1);
-               rcu_read_unlock_sched_notrace();
-               break;
-       }
-       default:
-               WARN_ON_ONCE(1);
-       }
-end:
-       return 0;
-}
-
-static const struct lttng_kernel_event_field *event_fields[] = {
-       lttng_kernel_static_event_field("ip",
-               lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16),
-               false, false),
-};
-
-static const struct lttng_kernel_tracepoint_class tp_class = {
-       .nr_fields = ARRAY_SIZE(event_fields),
-       .fields = event_fields,
-};
-
-/*
- * Create event description.
- */
-static
-int lttng_create_uprobe_event(const char *name, struct lttng_kernel_event_common *event)
-{
-       struct lttng_kernel_event_desc *desc;
-       int ret;
-
-       desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-       desc->tp_class = &tp_class;
-       desc->event_name = kstrdup(name, GFP_KERNEL);
-       if (!desc->event_name) {
-               ret = -ENOMEM;
-               goto error_str;
-       }
-       desc->owner = THIS_MODULE;
-       event->priv->desc = desc;
-
-       return 0;
-
-error_str:
-       kfree(desc);
-       return ret;
-}
-
-/*
- * Returns the inode struct from the current task and an fd. The inode is
- * grabbed by this function and must be put once we are done with it using
- * iput().
- */
-static struct inode *get_inode_from_fd(int fd)
-{
-       struct file *file;
-       struct inode *inode;
-
-       rcu_read_lock();
-       /*
-        * Returns the file backing the given fd. Needs to be done inside an RCU
-        * critical section.
-        */
-       file = lttng_lookup_fdget_rcu(fd);
-       if (file == NULL) {
-               printk(KERN_WARNING "LTTng: Cannot access file backing the fd(%d)\n", fd);
-               inode = NULL;
-               goto error;
-       }
-
-       /* Grab a reference on the inode. */
-       inode = igrab(file->f_path.dentry->d_inode);
-       if (inode == NULL)
-               printk(KERN_WARNING "LTTng: Cannot grab a reference on the inode.\n");
-
-error:
-       rcu_read_unlock();
-       if (file)
-               fput(file);
-       return inode;
-}
-
-
-static
-int lttng_uprobes_add_callsite(struct lttng_uprobe *uprobe,
-       struct lttng_kernel_abi_event_callsite __user *callsite,
-       int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs),
-       void *priv_data)
-{
-       int ret = 0;
-       struct lttng_uprobe_handler *uprobe_handler;
-
-       if (!priv_data) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       uprobe_handler = kzalloc(sizeof(struct lttng_uprobe_handler), GFP_KERNEL);
-       if (!uprobe_handler) {
-               printk(KERN_WARNING "LTTng: Error allocating uprobe_handler");
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       /* Ensure the memory we just allocated don't notify page faults. */
-       wrapper_vmalloc_sync_mappings();
-
-       uprobe_handler->event = priv_data;
-       uprobe_handler->up_consumer.handler = handler;
-
-       ret = copy_from_user(&uprobe_handler->offset, &callsite->u.uprobe.offset, sizeof(uint64_t));
-       if (ret) {
-               goto register_error;
-       }
-
-       ret = uprobe_register(uprobe->inode,
-                     uprobe_handler->offset, &uprobe_handler->up_consumer);
-       if (ret) {
-               printk(KERN_WARNING "LTTng: Error registering probe on inode %lu "
-                      "and offset 0x%llx\n", uprobe->inode->i_ino,
-                      uprobe_handler->offset);
-               ret = -1;
-               goto register_error;
-       }
-
-       list_add(&uprobe_handler->node, &uprobe->head);
-
-       return ret;
-
-register_error:
-       kfree(uprobe_handler);
-end:
-       return ret;
-}
-
-int lttng_uprobes_event_add_callsite(struct lttng_kernel_event_common *event,
-       struct lttng_kernel_abi_event_callsite __user *callsite)
-{
-       return lttng_uprobes_add_callsite(&event->priv->u.uprobe, callsite,
-               lttng_uprobes_event_handler_pre, event);
-}
-EXPORT_SYMBOL_GPL(lttng_uprobes_event_add_callsite);
-
-static
-int lttng_uprobes_register(struct lttng_uprobe *uprobe, int fd)
-{
-       int ret = 0;
-       struct inode *inode;
-
-       inode = get_inode_from_fd(fd);
-       if (!inode) {
-               printk(KERN_WARNING "LTTng: Cannot get inode from fd\n");
-               ret = -EBADF;
-               goto inode_error;
-       }
-       uprobe->inode = inode;
-       INIT_LIST_HEAD(&uprobe->head);
-
-inode_error:
-       return ret;
-}
-
-int lttng_uprobes_register_event(const char *name, int fd, struct lttng_kernel_event_common *event)
-{
-       int ret = 0;
-
-       ret = lttng_create_uprobe_event(name, event);
-       if (ret)
-               goto error;
-
-       ret = lttng_uprobes_register(&event->priv->u.uprobe, fd);
-       if (ret)
-               goto register_error;
-
-       return 0;
-
-register_error:
-       kfree(event->priv->desc->event_name);
-       kfree(event->priv->desc);
-error:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(lttng_uprobes_register_event);
-
-static
-void lttng_uprobes_unregister(struct inode *inode, struct list_head *head)
-{
-       struct lttng_uprobe_handler *iter, *tmp;
-
-       /*
-        * Iterate over the list of handler, remove each handler from the list
-        * and free the struct.
-        */
-       list_for_each_entry_safe(iter, tmp, head, node) {
-               uprobe_unregister(inode, iter->offset, &iter->up_consumer);
-               list_del(&iter->node);
-               kfree(iter);
-       }
-}
-
-void lttng_uprobes_unregister_event(struct lttng_kernel_event_common *event)
-{
-       lttng_uprobes_unregister(event->priv->u.uprobe.inode, &event->priv->u.uprobe.head);
-}
-EXPORT_SYMBOL_GPL(lttng_uprobes_unregister_event);
-
-void lttng_uprobes_destroy_event_private(struct lttng_kernel_event_common *event)
-{
-       iput(event->priv->u.uprobe.inode);
-       kfree(event->priv->desc->event_name);
-       kfree(event->priv->desc);
-}
-EXPORT_SYMBOL_GPL(lttng_uprobes_destroy_event_private);
-
-MODULE_LICENSE("GPL and additional rights");
-MODULE_AUTHOR("Yannick Brosseau");
-MODULE_DESCRIPTION("Linux Trace Toolkit Uprobes Support");
This page took 0.045524 seconds and 4 git commands to generate.