struct lttng_kprobe {
struct kprobe kp;
char *symbol_name;
+ uint64_t addr;
+ uint64_t offset;
+ kprobe_pre_handler_t pre_handler;
};
struct lttng_uprobe {
#endif
#ifdef CONFIG_KPROBES
-int lttng_kprobes_register_event(const char *name,
+int lttng_kprobes_init_event(const char *name,
const char *symbol_name,
uint64_t offset,
uint64_t addr,
struct lttng_kernel_event_common *event);
+int lttng_kprobes_register_event(struct lttng_kernel_event_common *event);
void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event);
void lttng_kprobes_destroy_event_private(struct lttng_kernel_event_common *event);
int lttng_kprobes_match_check(const char *symbol_name, uint64_t offset, uint64_t addr);
#else
static inline
-int lttng_kprobes_register_event(const char *name,
+int lttng_kprobes_init_event(const char *name,
const char *symbol_name,
uint64_t offset,
uint64_t addr,
{
return -ENOSYS;
}
+static inline
+int lttng_kprobes_register_event(struct lttng_kernel_event_common *event)
+{
+ return -ENOSYS;
+}
static inline
void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
fops = <tng_event_session_enabler_fops;
break;
- case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
case LTTNG_KERNEL_ABI_KRETPROBE:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
}
case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
+ {
+ struct lttng_event_recorder_enabler *event_enabler;
+
+ event_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+ event_param, channel);
+ if (event_enabler)
+ lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
+ priv = event_enabler;
+ break;
+ }
+
case LTTNG_KERNEL_ABI_UPROBE:
{
struct lttng_kernel_event_common *event;
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
fops = <tng_event_session_enabler_fops;
break;
- case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
+
case LTTNG_KERNEL_ABI_KRETPROBE:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
}
case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
+ {
+ struct lttng_event_counter_enabler *event_enabler;
+
+ event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+ event_param, key_param, NULL, channel);
+ if (event_enabler)
+ lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
+ priv = event_enabler;
+ break;
+ }
+
case LTTNG_KERNEL_ABI_UPROBE:
{
struct lttng_kernel_event_common *event;
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
fops = <tng_event_notifier_enabler_fops;
break;
- case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
+
case LTTNG_KERNEL_ABI_KRETPROBE:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
}
case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
+ {
+ struct lttng_event_notifier_enabler *enabler;
+
+ enabler = lttng_event_notifier_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+ event_notifier_param, event_notifier_group);
+ if (enabler)
+ lttng_event_notifier_enabler_group_add(event_notifier_group, enabler);
+ priv = enabler;
+ break;
+ }
+
case LTTNG_KERNEL_ABI_UPROBE:
{
struct lttng_kernel_event_common *event;
case LTTNG_KERNEL_ABI_DISABLE:
return lttng_event_enabler_disable(event_enabler);
case LTTNG_KERNEL_ABI_FILTER:
- return lttng_event_enabler_attach_filter_bytecode(event_enabler,
- (struct lttng_kernel_abi_filter_bytecode __user *) arg);
+ /*
+ * Filters are only supported by tracepoint and syscall instrumentation.
+ */
+ switch (event_enabler->event_param.instrumentation) {
+ case LTTNG_KERNEL_ABI_TRACEPOINT:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_SYSCALL:
+ return lttng_event_enabler_attach_filter_bytecode(event_enabler,
+ (struct lttng_kernel_abi_filter_bytecode __user *) arg);
+
+ default:
+ return -EINVAL;
+ }
case LTTNG_KERNEL_ABI_ADD_CALLSITE:
return -EINVAL;
default:
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
ret = -EINVAL;
break;
- case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
WRITE_ONCE(event->enabled, 1);
break;
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
ret = -EINVAL;
break;
- case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
case LTTNG_KERNEL_ABI_UPROBE:
WRITE_ONCE(event->enabled, 0);
break;
break;
case LTTNG_KERNEL_ABI_KPROBE:
- /*
- * Needs to be explicitly enabled after creation, since
- * we may want to apply filters.
- */
+ /* Event will be enabled by enabler sync. */
event->enabled = 0;
- event->priv->registered = 1;
- /*
- * Populate lttng_event structure before event
- * registration.
- */
- smp_wmb();
- ret = lttng_kprobes_register_event(event_name,
+ event->priv->registered = 0;
+ ret = lttng_kprobes_init_event(event_name,
event_param->u.kprobe.symbol_name,
event_param->u.kprobe.offset,
event_param->u.kprobe.addr,
ret = -EINVAL;
goto register_error;
}
+ /*
+ * Populate lttng_event structure before event
+ * registration.
+ */
+ smp_wmb();
ret = try_module_get(event->priv->desc->owner);
WARN_ON_ONCE(!ret);
- ret = lttng_append_event_to_channel_map(event_enabler, event, event_name);
- WARN_ON_ONCE(ret);
break;
case LTTNG_KERNEL_ABI_KRETPROBE:
return counter->ops->priv->counter_get_max_nr_elem(counter, max_nr_elem);
}
-/* Only used for tracepoints and system calls for now. */
+/* Used for tracepoints, system calls, and kprobe. */
static
void register_event(struct lttng_kernel_event_common *event)
{
break;
case LTTNG_KERNEL_ABI_KPROBE:
- lttng_fallthrough;
+ ret = lttng_kprobes_register_event(event);
+ break;
+
case LTTNG_KERNEL_ABI_UPROBE:
ret = 0;
break;
}
break;
+ case LTTNG_KERNEL_ABI_KPROBE:
+ desc_name = desc->event_name;
+ switch (enabler->format_type) {
+ case LTTNG_ENABLER_FORMAT_STAR_GLOB:
+ return -EINVAL;
+ case LTTNG_ENABLER_FORMAT_NAME:
+ return lttng_match_enabler_name(desc_name, enabler_name);
+ default:
+ return -EINVAL;
+ }
+ break;
+
+
default:
WARN_ON_ONCE(1);
return -EINVAL;
}
}
+/* Try to create the event associated with this kprobe enabler. */
+static
+void lttng_event_enabler_create_kprobe_event_if_missing(struct lttng_event_enabler_common *event_enabler)
+{
+ struct lttng_kernel_event_common *event;
+
+ event = _lttng_kernel_event_create(event_enabler, NULL, NULL);
+ if (IS_ERR(event)) {
+ if (PTR_ERR(event) != -EEXIST) {
+ printk(KERN_INFO "LTTng: Unable to create kprobe event %s\n",
+ event_enabler->event_param.name);
+ }
+ }
+}
+
/*
* Create event if it is missing and present in the list of tracepoint probes.
* Should be called with sessions mutex held.
WARN_ON_ONCE(ret);
break;
+ case LTTNG_KERNEL_ABI_KPROBE:
+ lttng_event_enabler_create_kprobe_event_if_missing(event_enabler);
+ break;
+
default:
WARN_ON_ONCE(1);
break;
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
/* Enable events */
list_for_each_entry(enabler_ref, &event->priv->enablers_ref_head, node) {
if (enabler_ref->ref->enabled) {
case LTTNG_KERNEL_ABI_TRACEPOINT:
lttng_fallthrough;
case LTTNG_KERNEL_ABI_SYSCALL:
+ lttng_fallthrough;
+ case LTTNG_KERNEL_ABI_KPROBE:
return true;
default:
.fields = event_fields,
};
+static
+int lttng_kp_init(struct lttng_kprobe *lttng_kp, const char *symbol_name, uint64_t offset, uint64_t addr,
+ kprobe_pre_handler_t pre_handler)
+{
+ /* Kprobes expects a NULL symbol name if unused */
+ if (symbol_name[0] == '\0')
+ symbol_name = NULL;
+
+ lttng_kp->pre_handler = pre_handler;
+
+ if (symbol_name) {
+ lttng_kp->symbol_name =
+ kzalloc(LTTNG_KERNEL_ABI_SYM_NAME_LEN * sizeof(char),
+ GFP_KERNEL);
+ if (!lttng_kp->symbol_name)
+ return -ENOMEM;
+ memcpy(lttng_kp->symbol_name, symbol_name,
+ LTTNG_KERNEL_ABI_SYM_NAME_LEN * sizeof(char));
+ }
+
+ lttng_kp->offset = offset;
+ lttng_kp->addr = addr;
+ return 0;
+}
+
/*
- * Create event description
+ * Initialize event
*/
-static
-int lttng_create_kprobe_event(const char *name, struct lttng_kernel_event_common *event)
+int lttng_kprobes_init_event(const char *name,
+ const char *symbol_name,
+ uint64_t offset,
+ uint64_t addr,
+ struct lttng_kernel_event_common *event)
{
struct lttng_kernel_event_desc *desc;
int ret;
}
desc->owner = THIS_MODULE;
event->priv->desc = desc;
-
+ ret = lttng_kp_init(&event->priv->u.kprobe, symbol_name, offset, addr,
+ lttng_kprobes_event_handler_pre);
+ if (ret)
+ goto error_init;
return 0;
+error_init:
+ kfree(desc->event_name);
error_str:
kfree(desc);
return ret;
}
static
-int _lttng_kprobes_register(const char *symbol_name,
- uint64_t offset,
- uint64_t addr,
- struct lttng_kprobe *lttng_kp,
- kprobe_pre_handler_t pre_handler)
+int _lttng_kprobes_register(struct lttng_kprobe *lttng_kp)
{
- int ret;
-
- /* Kprobes expects a NULL symbol name if unused */
- if (symbol_name[0] == '\0')
- symbol_name = NULL;
-
- memset(<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,
*/
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;
+ /*
+ * Populate struct kprobe on each registration because kprobe internally
+ * does destructive changes to its state (e.g. addr=NULL).
+ */
+ memset(<tng_kp->kp, 0, sizeof(lttng_kp->kp));
+ lttng_kp->kp.symbol_name = lttng_kp->symbol_name;
+ lttng_kp->kp.addr = (void *)(unsigned long)lttng_kp->addr;
+ lttng_kp->kp.offset = lttng_kp->offset;
+ lttng_kp->kp.pre_handler = lttng_kp->pre_handler;
+ return register_kprobe(<tng_kp->kp);
}
-int lttng_kprobes_register_event(const char *name,
- const char *symbol_name,
- uint64_t offset,
- uint64_t addr,
- struct lttng_kernel_event_common *event)
+int lttng_kprobes_register_event(struct lttng_kernel_event_common *event)
{
- int ret;
-
- ret = lttng_create_kprobe_event(name, event);
- if (ret)
- goto error;
-
- ret = _lttng_kprobes_register(symbol_name, offset, addr,
- &event->priv->u.kprobe, lttng_kprobes_event_handler_pre);
- if (ret)
- goto register_error;
-
- return 0;
-
-register_error:
- kfree(event->priv->desc->event_name);
- kfree(event->priv->desc);
-error:
- return ret;
+ return _lttng_kprobes_register(&event->priv->u.kprobe);
}
void lttng_kprobes_unregister_event(struct lttng_kernel_event_common *event)
int lttng_kprobes_match_check(const char *symbol_name, uint64_t offset, uint64_t addr)
{
struct lttng_kprobe lttng_kp;
- int ret;
+ int ret = 0;
memset(<tng_kp, 0, sizeof(lttng_kp));
- ret = _lttng_kprobes_register(symbol_name, offset, addr, <tng_kp, NULL);
+ ret = lttng_kp_init(<tng_kp, symbol_name, offset, addr, NULL);
if (ret)
- return -ENOENT;
+ return ret;
+ ret = _lttng_kprobes_register(<tng_kp);
+ if (ret) {
+ ret = -ENOENT;
+ goto end;
+ }
unregister_kprobe(<tng_kp.kp);
+end:
kfree(lttng_kp.symbol_name);
- return 0;
+ return ret;
}