From: Mathieu Desnoyers Date: Tue, 22 Feb 2022 16:56:29 +0000 (-0500) Subject: Fix: circular dependency on symbol lttng_id_tracker_lookup X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=0c2c6606eb66cb5222ab7a2a4f8329fd5dfdef70;p=lttng-modules.git Fix: circular dependency on symbol lttng_id_tracker_lookup 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 Change-Id: Iea80c8054054b341e1836c8675c04e00424608fc --- diff --git a/src/Kbuild b/src/Kbuild index a341fd9b..3fa1807d 100644 --- a/src/Kbuild +++ b/src/Kbuild @@ -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 index 00000000..bb6decc0 --- /dev/null +++ b/src/lttng-kprobes.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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), <tng_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, ¬if_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(<tng_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(<tng_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 "); +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 index 00000000..55866a82 --- /dev/null +++ b/src/lttng-kretprobes.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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), <tng_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(<tng_krp->kref_alloc); + kref_get(<tng_krp->kref_alloc); /* inc refcount to 2, no overflow. */ + kref_init(<tng_krp->kref_register); + kref_get(<tng_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(<tng_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(<tng_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 "); +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 index 00000000..bf4305f3 --- /dev/null +++ b/src/lttng-uprobes.c @@ -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 + * Copyright (C) 2009-2012 Mathieu Desnoyers + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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), <tng_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, ¬if_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"); diff --git a/src/probes/Kbuild b/src/probes/Kbuild index c4273e01..f9677678 100644 --- a/src/probes/Kbuild +++ b/src/probes/Kbuild @@ -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 index bb6decc0..00000000 --- a/src/probes/lttng-kprobes.c +++ /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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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), <tng_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, ¬if_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(<tng_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(<tng_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 "); -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 index 55866a82..00000000 --- a/src/probes/lttng-kretprobes.c +++ /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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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), <tng_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(<tng_krp->kref_alloc); - kref_get(<tng_krp->kref_alloc); /* inc refcount to 2, no overflow. */ - kref_init(<tng_krp->kref_register); - kref_get(<tng_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(<tng_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(<tng_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 "); -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 index bf4305f3..00000000 --- a/src/probes/lttng-uprobes.c +++ /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 - * Copyright (C) 2009-2012 Mathieu Desnoyers - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -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), <tng_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, ¬if_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");