* 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);
#include <linux/fs.h>
+#define LTTNG_KPROBE_SYM_NAME_LEN 128
+
enum lttng_kernel_instrumentation {
LTTNG_KERNEL_TRACEPOINTS,
LTTNG_KERNEL_KPROBES,
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.
*/
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 {
* 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)
{
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);
}
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);
}
#include <linux/list.h>
#include <linux/uuid.h>
+#include <linux/kprobes.h>
#include "ltt-debugfs-abi.h"
struct ltt_channel;
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;
};
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);
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 */
obj-m += lttng-probe-block.o
obj-m += lttng-probe-syscalls.o
+obj-m += lttng-kprobes.o
+
endif
else
--- /dev/null
+/*
+ * (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");