From d6d808f3780d0b519aaf966e66df501730db7d13 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 18 May 2011 21:16:07 -0400 Subject: [PATCH] Add kprobes support Signed-off-by: Mathieu Desnoyers --- ltt-debugfs-abi.c | 4 ++-- ltt-debugfs-abi.h | 18 ++++++++++++------ ltt-events.c | 31 ++++++++++++++++++++++++++++--- ltt-events.h | 11 ++++++++++- probes/Makefile | 2 ++ probes/lttng-kprobes.c | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 probes/lttng-kprobes.c diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c index 54016466..d013fa5a 100644 --- a/ltt-debugfs-abi.c +++ b/ltt-debugfs-abi.c @@ -398,11 +398,11 @@ int lttng_abi_create_event(struct file *channel_file, * We tolerate no failure path after event creation. It will stay * invariant for the rest of the session. */ - event = ltt_event_create(channel, event_name, event_param.instrumentation, + event = ltt_event_create(channel, event_name, &event_param, event_desc, NULL); if (!event) { - goto event_error; ret = -EEXIST; + goto event_error; } event_file->private_data = event; fd_install(event_fd, event_file); diff --git a/ltt-debugfs-abi.h b/ltt-debugfs-abi.h index ef2554b8..ecbd5413 100644 --- a/ltt-debugfs-abi.h +++ b/ltt-debugfs-abi.h @@ -11,6 +11,8 @@ #include +#define LTTNG_KPROBE_SYM_NAME_LEN 128 + enum lttng_kernel_instrumentation { LTTNG_KERNEL_TRACEPOINTS, LTTNG_KERNEL_KPROBES, @@ -28,11 +30,6 @@ struct lttng_kernel_channel { unsigned int read_timer_interval; }; -struct lttng_kernel_event { - enum lttng_kernel_instrumentation instrumentation; - char name[]; -}; - /* * Either addr is used, or symbol_name and offset. */ @@ -40,7 +37,16 @@ struct lttng_kernel_kprobe { uint64_t addr; uint64_t offset; - char symbol_name[]; + char symbol_name[LTTNG_KPROBE_SYM_NAME_LEN]; +}; + +struct lttng_kernel_event { + enum lttng_kernel_instrumentation instrumentation; + /* Per instrumentation type configuration */ + union { + struct lttng_kernel_kprobe kprobe; + } u; + char name[]; }; struct lttng_kernel_tracer_version { diff --git a/ltt-events.c b/ltt-events.c index 526fb823..ec5d6830 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -202,7 +202,7 @@ void _ltt_channel_destroy(struct ltt_channel *chan) * Supports event creation while tracing session is active. */ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, - enum lttng_kernel_instrumentation instrumentation, + struct lttng_kernel_event *event_param, const struct lttng_event_desc *event_desc, void *filter) { @@ -226,16 +226,36 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, event->desc = event_desc; event->filter = filter; event->id = chan->free_event_id++; - event->instrumentation = instrumentation; + event->instrumentation = event_param->instrumentation; /* Populate ltt_event structure before tracepoint registration. */ smp_wmb(); - switch (instrumentation) { + switch (event_param->instrumentation) { case LTTNG_KERNEL_TRACEPOINTS: ret = tracepoint_probe_register(name, event_desc->probe_callback, event); if (ret) goto register_error; break; + case LTTNG_KERNEL_KPROBES: + event->u.kprobe.kp.pre_handler = lttng_kprobes_handler_pre; + event->u.kprobe.symbol_name = + kzalloc(LTTNG_KPROBE_SYM_NAME_LEN * sizeof(char), + GFP_KERNEL); + if (!event->u.kprobe.symbol_name) + goto register_error; + memcpy(event->u.kprobe.symbol_name, + event_param->u.kprobe.symbol_name, + LTTNG_KPROBE_SYM_NAME_LEN * sizeof(char)); + event->u.kprobe.kp.symbol_name = + event->u.kprobe.symbol_name; + event->u.kprobe.kp.offset = event_param->u.kprobe.offset; + event->u.kprobe.kp.addr = (void *) event_param->u.kprobe.addr; + ret = register_kprobe(&event->u.kprobe.kp); + if (ret) { + kfree(event->u.kprobe.symbol_name); + goto register_error; + } + break; default: WARN_ON_ONCE(1); } @@ -273,6 +293,11 @@ int _ltt_event_unregister(struct ltt_event *event) if (ret) return ret; break; + case LTTNG_KERNEL_KPROBES: + unregister_kprobe(&event->u.kprobe.kp); + kfree(event->u.kprobe.symbol_name); + ret = 0; + break; default: WARN_ON_ONCE(1); } diff --git a/ltt-events.h b/ltt-events.h index 70761853..42e12c0a 100644 --- a/ltt-events.h +++ b/ltt-events.h @@ -11,6 +11,7 @@ #include #include +#include #include "ltt-debugfs-abi.h" struct ltt_channel; @@ -129,6 +130,12 @@ struct ltt_event { const struct lttng_event_desc *desc; void *filter; enum lttng_kernel_instrumentation instrumentation; + union { + struct { + struct kprobe kp; + char *symbol_name; + } kprobe; + } u; struct list_head list; /* Event list */ int metadata_dumped:1; }; @@ -209,7 +216,7 @@ void _ltt_channel_destroy(struct ltt_channel *chan); struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, - enum lttng_kernel_instrumentation instrumentation, + struct lttng_kernel_event *event_param, const struct lttng_event_desc *event_desc, void *filter); int ltt_event_unregister(struct ltt_event *event); @@ -227,4 +234,6 @@ void ltt_event_put(const struct lttng_event_desc *desc); int ltt_probes_init(void); void ltt_probes_exit(void); +void lttng_kprobes_handler_pre(struct kprobe *p, struct pt_regs *regs); + #endif /* _LTT_EVENTS_H */ diff --git a/probes/Makefile b/probes/Makefile index 81563b20..77ff09a2 100644 --- a/probes/Makefile +++ b/probes/Makefile @@ -16,6 +16,8 @@ obj-m += lttng-probe-irq.o obj-m += lttng-probe-block.o obj-m += lttng-probe-syscalls.o +obj-m += lttng-kprobes.o + endif else diff --git a/probes/lttng-kprobes.c b/probes/lttng-kprobes.c new file mode 100644 index 00000000..eb6e16a0 --- /dev/null +++ b/probes/lttng-kprobes.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2009-2011 - + * Mathieu Desnoyers + * + * LTTng kprobes integration module. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include "../ltt-events.h" +#include "../wrapper/ringbuffer/frontend_types.h" +#include "../ltt-tracer.h" + +void lttng_kprobes_handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + struct ltt_event *event = + container_of(p, struct ltt_event, u.kprobe.kp); + struct ltt_channel *chan = event->chan; + struct lib_ring_buffer_ctx ctx; + int ret; + unsigned long data = (unsigned long) p->addr; + + if (!ACCESS_ONCE(chan->session->active)) + return; + lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, sizeof(data), + ltt_alignof(data), -1); + ret = chan->ops->event_reserve(&ctx); + if (ret < 0) + return; + lib_ring_buffer_align_ctx(&ctx, ltt_alignof(data)); + chan->ops->event_write(&ctx, &data, sizeof(data)); + chan->ops->event_commit(&ctx); +} +EXPORT_SYMBOL_GPL(lttng_kprobes_handler_pre); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit Kprobes Support"); -- 2.34.1