Add kprobes support
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 19 May 2011 01:16:07 +0000 (21:16 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 19 May 2011 01:16:07 +0000 (21:16 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
ltt-debugfs-abi.c
ltt-debugfs-abi.h
ltt-events.c
ltt-events.h
probes/Makefile
probes/lttng-kprobes.c [new file with mode: 0644]

index 540164662e2b315fb4039bebb8f621d9f283708b..d013fa5a86a4e1fd33507ceff92dab0c509386de 100644 (file)
@@ -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);
index ef2554b81bce95f546e799ac1ad4021a5d118bca..ecbd5413825f6fe8d877293ace6320b81d1fd56c 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/fs.h>
 
+#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 {
index 526fb823952219e74cbe1fcebe64da69b7a05865..ec5d6830d4355fa64d91b1870d9443874dae8bd3 100644 (file)
@@ -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);
        }
index 7076185308f59fce9140ff87e8a438a28ba7ef27..42e12c0af19172c6ddc5f67b44cbf73b0d851edd 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/list.h>
 #include <linux/uuid.h>
+#include <linux/kprobes.h>
 #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 */
index 81563b20b6e29ba2818a458de080926882468383..77ff09a2e99288156a52d1d8ee7a26bb673e30a5 100644 (file)
@@ -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 (file)
index 0000000..eb6e16a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * (C) Copyright       2009-2011 -
+ *             Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * LTTng kprobes integration module.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#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");
This page took 0.032016 seconds and 4 git commands to generate.