goto name_error;
}
event_name[PATH_MAX - 1] = '\0';
- event_param.u.kprobe.symbol_name[LTTNG_KPROBE_SYM_NAME_LEN - 1] = '\0';
-
+ switch (event_param.instrumentation) {
+ case LTTNG_KERNEL_KPROBES:
+ event_param.u.kprobe.symbol_name[LTTNG_SYM_NAME_LEN - 1] = '\0';
+ break;
+ case LTTNG_KERNEL_FUNCTION_TRACER:
+ event_param.u.ftrace.symbol_name[LTTNG_SYM_NAME_LEN - 1] = '\0';
+ break;
+ default:
+ break;
+ }
event_fd = get_unused_fd();
if (event_fd < 0) {
ret = event_fd;
#include <linux/fs.h>
-#define LTTNG_KPROBE_SYM_NAME_LEN 128
+#define LTTNG_SYM_NAME_LEN 128
enum lttng_kernel_instrumentation {
LTTNG_KERNEL_TRACEPOINTS,
uint64_t addr;
uint64_t offset;
- char symbol_name[LTTNG_KPROBE_SYM_NAME_LEN];
+ char symbol_name[LTTNG_SYM_NAME_LEN];
};
struct lttng_kernel_function_tracer {
- char symbol_name[LTTNG_KPROBE_SYM_NAME_LEN];
+ char symbol_name[LTTNG_SYM_NAME_LEN];
};
struct lttng_kernel_event {
if (ret)
goto register_error;
break;
+ case LTTNG_KERNEL_FUNCTION_TRACER:
+ ret = lttng_ftrace_register(name,
+ event_param->u.ftrace.symbol_name,
+ event);
+ if (ret)
+ goto register_error;
+ break;
default:
WARN_ON_ONCE(1);
}
lttng_kprobes_unregister(event);
ret = 0;
break;
+ case LTTNG_KERNEL_FUNCTION_TRACER:
+ lttng_ftrace_unregister(event);
+ ret = 0;
+ break;
default:
WARN_ON_ONCE(1);
}
switch (field->type.atype) {
case atype_integer:
ret = lttng_metadata_printf(session,
- " integer { size = %u; align = %u; signed = %u;%s } %s;\n",
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n",
field->type.u.basic.integer.size,
field->type.u.basic.integer.alignment,
field->type.u.basic.integer.signedness,
+ (field->type.u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (field->type.u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ field->type.u.basic.integer.base,
#ifdef __BIG_ENDIAN
field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
elem_type = &field->type.u.array.elem_type;
ret = lttng_metadata_printf(session,
- " integer { size = %u; align = %u; signed = %u;%s } %s[%u];\n",
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n",
elem_type->u.basic.integer.size,
elem_type->u.basic.integer.alignment,
elem_type->u.basic.integer.signedness,
+ (elem_type->u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ elem_type->u.basic.integer.base,
#ifdef __BIG_ENDIAN
elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
elem_type = &field->type.u.sequence.elem_type;
length_type = &field->type.u.sequence.length_type;
ret = lttng_metadata_printf(session,
- " integer { size = %u; align = %u; signed = %u;%s } %s[ integer { size = %u; align = %u; signed = %u;%s } ];\n",
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n",
+ length_type->u.basic.integer.size,
+ length_type->u.basic.integer.alignment,
+ length_type->u.basic.integer.signedness,
+ (length_type->u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (length_type->u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ length_type->u.basic.integer.base,
+#ifdef __BIG_ENDIAN
+ length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
+#else
+ length_type->u.basic.integer.reverse_byte_order
+? " byte_order = be;" : "",
+#endif
+ field->name,
elem_type->u.basic.integer.size,
elem_type->u.basic.integer.alignment,
elem_type->u.basic.integer.signedness,
+ (elem_type->u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ elem_type->u.basic.integer.base,
#ifdef __BIG_ENDIAN
elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
#endif
field->name,
- length_type->u.basic.integer.size,
- length_type->u.basic.integer.alignment,
- length_type->u.basic.integer.signedness,
-#ifdef __BIG_ENDIAN
- length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
-#else
- length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : ""
-#endif
+ field->name
);
break;
}
case atype_string:
+ /* Default encoding is UTF8 */
ret = lttng_metadata_printf(session,
" string%s %s;\n",
field->type.u.basic.string.encoding == lttng_encode_ASCII ?
/* Update the string_encodings name table in lttng-types.c along with this enum */
enum lttng_string_encodings {
- lttng_encode_UTF8 = 0,
- lttng_encode_ASCII = 1,
+ lttng_encode_none = 0,
+ lttng_encode_UTF8 = 1,
+ lttng_encode_ASCII = 2,
NR_STRING_ENCODINGS,
};
const char *string;
};
-#define __type_integer(_type, _byte_order) \
+#define __type_integer(_type, _byte_order, _base) \
{ \
.atype = atype_integer, \
.u.basic.integer = \
.alignment = ltt_alignof(_type) * CHAR_BIT, \
.signedness = is_signed_type(_type), \
.reverse_byte_order = _byte_order != __BYTE_ORDER, \
+ .base = _base, \
+ .encoding = lttng_encode_none, \
}, \
} \
unsigned short alignment; /* in bits */
unsigned int signedness:1;
unsigned int reverse_byte_order:1;
+ unsigned int base; /* 2, 8, 10, 16, for pretty print */
+ enum lttng_string_encodings encoding;
};
union _lttng_basic_type {
struct kprobe kp;
char *symbol_name;
} kprobe;
+ struct {
+ char *symbol_name;
+ } ftrace;
} u;
struct list_head list; /* Event list */
int metadata_dumped:1;
struct ltt_event *event);
void lttng_kprobes_unregister(struct ltt_event *event);
+#ifdef CONFIG_DYNAMIC_FTRACE
+int lttng_ftrace_register(const char *name,
+ const char *symbol_name,
+ struct ltt_event *event);
+void lttng_ftrace_unregister(struct ltt_event *event);
+#else
+static inline
+int lttng_ftrace_register(const char *name,
+ const char *symbol_name,
+ struct ltt_event *event)
+{
+ return 0;
+}
+
+static inline
+void lttng_ftrace_unregister(struct ltt_event *event)
+{
+}
+#endif
#endif /* _LTT_EVENTS_H */
obj-m += lttng-kprobes.o
+ifneq ($(CONFIG_DYNAMIC_FTRACE),)
+obj-m += lttng-ftrace.o
+endif
+
endif
else
#define __field(_type, _item) \
{ \
.name = #_item, \
- .type = __type_integer(_type, __BYTE_ORDER), \
+ .type = __type_integer(_type, __BYTE_ORDER, 10), \
},
#undef __field_ext
#define __field_network(_type, _item) \
{ \
.name = #_item, \
- .type = __type_integer(_type, __BIG_ENDIAN), \
+ .type = __type_integer(_type, __BIG_ENDIAN, 10), \
},
#undef __array
.u.array = \
{ \
.length = _length, \
- .elem_type = __type_integer(_type, __BYTE_ORDER), \
+ .elem_type = __type_integer(_type, __BYTE_ORDER, 10), \
}, \
}, \
},
.atype = atype_sequence, \
.u.sequence = \
{ \
- .length_type = __type_integer(u32, __BYTE_ORDER), \
- .elem_type = __type_integer(_type, __BYTE_ORDER), \
+ .length_type = __type_integer(u32, __BYTE_ORDER, 10), \
+ .elem_type = __type_integer(_type, __BYTE_ORDER, 10), \
}, \
}, \
},
--- /dev/null
+/*
+ * (C) Copyright 2009-2011 -
+ * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * LTTng function tracer integration module.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#include <linux/module.h>
+#include <linux/ftrace.h>
+#include <linux/slab.h>
+#include "../ltt-events.h"
+#include "../wrapper/ringbuffer/frontend_types.h"
+#include "../ltt-tracer.h"
+
+static
+int lttng_ftrace_handler(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ struct ltt_event *event = *data;
+ struct ltt_channel *chan = event->chan;
+ struct lib_ring_buffer_ctx ctx;
+ struct {
+ unsigned long ip;
+ unsigned long parent_ip;
+ } payload;
+ int ret;
+
+ if (!ACCESS_ONCE(chan->session->active))
+ return 0;
+ lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL,
+ sizeof(payload), ltt_alignof(payload), -1);
+ ret = chan->ops->event_reserve(&ctx);
+ if (ret < 0)
+ return 0;
+ payload.ip = ip;
+ payload.parent_ip = parent_ip;
+ lib_ring_buffer_align_ctx(&ctx, ltt_alignof(payload));
+ chan->ops->event_write(&ctx, &payload, sizeof(payload));
+ chan->ops->event_commit(&ctx);
+ return 0;
+}
+
+/*
+ * Create event description
+ */
+static
+int lttng_create_ftrace_event(const char *name, struct ltt_event *event)
+{
+ struct lttng_event_field *fields;
+ struct lttng_event_desc *desc;
+ int ret;
+
+ desc = kzalloc(sizeof(*event->desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+ desc->name = kstrdup(name, GFP_KERNEL);
+ if (!desc->name) {
+ ret = -ENOMEM;
+ goto error_str;
+ }
+ desc->nr_fields = 2;
+ desc->fields = fields =
+ kzalloc(2 * sizeof(struct lttng_event_field), GFP_KERNEL);
+ fields[0].name = "ip";
+ fields[0].type.atype = atype_integer;
+ fields[0].type.u.basic.integer.size = sizeof(unsigned long);
+ fields[0].type.u.basic.integer.alignment = ltt_alignof(unsigned long);
+ fields[0].type.u.basic.integer.signedness = 0;
+ fields[0].type.u.basic.integer.reverse_byte_order = 0;
+ fields[0].type.u.basic.integer.base = 16;
+ fields[0].type.u.basic.integer.encoding = lttng_encode_none;
+
+ fields[1].name = "parent_ip";
+ fields[1].type.atype = atype_integer;
+ fields[1].type.u.basic.integer.size = sizeof(unsigned long);
+ fields[1].type.u.basic.integer.alignment = ltt_alignof(unsigned long);
+ fields[1].type.u.basic.integer.signedness = 0;
+ fields[1].type.u.basic.integer.reverse_byte_order = 0;
+ fields[1].type.u.basic.integer.base = 16;
+ fields[1].type.u.basic.integer.encoding = lttng_encode_none;
+
+ event->desc = desc;
+
+ return 0;
+
+error_str:
+ kfree(desc);
+ return ret;
+}
+
+static
+struct ftrace_probe_ops lttng_ftrace_ops = {
+ .func = lttng_ftrace_handler,
+};
+
+int lttng_ftrace_register(const char *name,
+ const char *symbol_name,
+ struct ltt_event *event)
+{
+ int ret;
+
+ ret = lttng_create_ftrace_event(name, event);
+ if (ret)
+ goto error;
+
+ event->u.ftrace.symbol_name = kstrdup(name, GFP_KERNEL);
+ if (!event->u.ftrace.symbol_name)
+ goto name_error;
+
+ ret = register_ftrace_function_probe(symbol_name,
+ <tng_ftrace_ops, event);
+ if (ret)
+ goto register_error;
+ return 0;
+
+register_error:
+ kfree(event->u.ftrace.symbol_name);
+name_error:
+ kfree(event->desc->name);
+ kfree(event->desc);
+error:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(lttng_ftrace_register);
+
+void lttng_ftrace_unregister(struct ltt_event *event)
+{
+ unregister_ftrace_function_probe(event->u.ftrace.symbol_name,
+ <tng_ftrace_ops, event);
+ kfree(event->u.ftrace.symbol_name);
+ kfree(event->desc->name);
+ kfree(event->desc);
+}
+EXPORT_SYMBOL_GPL(lttng_ftrace_unregister);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Ftrace Support");
field->type.u.basic.integer.alignment = ltt_alignof(unsigned long);
field->type.u.basic.integer.signedness = 0;
field->type.u.basic.integer.reverse_byte_order = 0;
+ field->type.u.basic.integer.base = 16;
+ field->type.u.basic.integer.encoding = lttng_encode_none;
event->desc = desc;
return 0;
memset(&event->u.kprobe.kp, 0, sizeof(event->u.kprobe.kp));
event->u.kprobe.kp.pre_handler = lttng_kprobes_handler_pre;
event->u.kprobe.symbol_name =
- kzalloc(LTTNG_KPROBE_SYM_NAME_LEN * sizeof(char),
+ kzalloc(LTTNG_SYM_NAME_LEN * sizeof(char),
GFP_KERNEL);
if (!event->u.kprobe.symbol_name) {
ret = -ENOMEM;
goto name_error;
}
memcpy(event->u.kprobe.symbol_name, symbol_name,
- LTTNG_KPROBE_SYM_NAME_LEN * sizeof(char));
+ LTTNG_SYM_NAME_LEN * sizeof(char));
event->u.kprobe.kp.symbol_name =
event->u.kprobe.symbol_name;
event->u.kprobe.kp.offset = offset;
#define TRACE_EVENT_TYPE___enum(_name, _container_type) \
{ \
.name = #_name, \
- .container_type = __type_integer(_container_type, __BYTE_ORDER), \
+ .container_type = __type_integer(_container_type, __BYTE_ORDER, 10), \
.entries = __trace_event_enum_##_name, \
.len = ARRAY_SIZE(__trace_event_enum_##_name), \
},