From e0a7a7c4a6a88a60ae40baeb4f4656f58175993a Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 18 May 2011 23:46:54 -0400 Subject: [PATCH] Function tracer support Signed-off-by: Mathieu Desnoyers --- ltt-debugfs-abi.c | 12 +++- ltt-debugfs-abi.h | 6 +- ltt-events.c | 62 ++++++++++++++---- ltt-events.h | 33 +++++++++- probes/Makefile | 4 ++ probes/lttng-events.h | 10 +-- probes/lttng-ftrace.c | 139 +++++++++++++++++++++++++++++++++++++++++ probes/lttng-kprobes.c | 6 +- probes/lttng-types.h | 2 +- 9 files changed, 247 insertions(+), 27 deletions(-) create mode 100644 probes/lttng-ftrace.c diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c index 9139e5a1..a889378f 100644 --- a/ltt-debugfs-abi.c +++ b/ltt-debugfs-abi.c @@ -367,8 +367,16 @@ int lttng_abi_create_event(struct file *channel_file, 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; diff --git a/ltt-debugfs-abi.h b/ltt-debugfs-abi.h index 411c37b7..74ad764d 100644 --- a/ltt-debugfs-abi.h +++ b/ltt-debugfs-abi.h @@ -11,7 +11,7 @@ #include -#define LTTNG_KPROBE_SYM_NAME_LEN 128 +#define LTTNG_SYM_NAME_LEN 128 enum lttng_kernel_instrumentation { LTTNG_KERNEL_TRACEPOINTS, @@ -38,11 +38,11 @@ struct lttng_kernel_kprobe { 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 { diff --git a/ltt-events.c b/ltt-events.c index cf4fc8b7..20db4c55 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -247,6 +247,13 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, 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); } @@ -291,6 +298,10 @@ int _ltt_event_unregister(struct ltt_event *event) lttng_kprobes_unregister(event); ret = 0; break; + case LTTNG_KERNEL_FUNCTION_TRACER: + lttng_ftrace_unregister(event); + ret = 0; + break; default: WARN_ON_ONCE(1); } @@ -396,10 +407,16 @@ int _ltt_fields_metadata_statedump(struct ltt_session *session, 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 @@ -419,10 +436,16 @@ int _ltt_fields_metadata_statedump(struct ltt_session *session, 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 @@ -439,29 +462,46 @@ int _ltt_fields_metadata_statedump(struct ltt_session *session, 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 ? diff --git a/ltt-events.h b/ltt-events.h index 030ffe02..e10c66c8 100644 --- a/ltt-events.h +++ b/ltt-events.h @@ -32,8 +32,9 @@ enum abstract_types { /* 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, }; @@ -42,7 +43,7 @@ struct lttng_enum_entry { const char *string; }; -#define __type_integer(_type, _byte_order) \ +#define __type_integer(_type, _byte_order, _base) \ { \ .atype = atype_integer, \ .u.basic.integer = \ @@ -51,6 +52,8 @@ struct lttng_enum_entry { .alignment = ltt_alignof(_type) * CHAR_BIT, \ .signedness = is_signed_type(_type), \ .reverse_byte_order = _byte_order != __BYTE_ORDER, \ + .base = _base, \ + .encoding = lttng_encode_none, \ }, \ } \ @@ -59,6 +62,8 @@ struct lttng_integer_type { 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 { @@ -135,6 +140,9 @@ struct ltt_event { struct kprobe kp; char *symbol_name; } kprobe; + struct { + char *symbol_name; + } ftrace; } u; struct list_head list; /* Event list */ int metadata_dumped:1; @@ -240,4 +248,23 @@ int lttng_kprobes_register(const char *name, 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 */ diff --git a/probes/Makefile b/probes/Makefile index 77ff09a2..14a7c93b 100644 --- a/probes/Makefile +++ b/probes/Makefile @@ -18,6 +18,10 @@ obj-m += lttng-probe-syscalls.o obj-m += lttng-kprobes.o +ifneq ($(CONFIG_DYNAMIC_FTRACE),) +obj-m += lttng-ftrace.o +endif + endif else diff --git a/probes/lttng-events.h b/probes/lttng-events.h index 5ee61bc6..8ffc23a2 100644 --- a/probes/lttng-events.h +++ b/probes/lttng-events.h @@ -78,7 +78,7 @@ void trace_##_name(_proto); #define __field(_type, _item) \ { \ .name = #_item, \ - .type = __type_integer(_type, __BYTE_ORDER), \ + .type = __type_integer(_type, __BYTE_ORDER, 10), \ }, #undef __field_ext @@ -88,7 +88,7 @@ void trace_##_name(_proto); #define __field_network(_type, _item) \ { \ .name = #_item, \ - .type = __type_integer(_type, __BIG_ENDIAN), \ + .type = __type_integer(_type, __BIG_ENDIAN, 10), \ }, #undef __array @@ -101,7 +101,7 @@ void trace_##_name(_proto); .u.array = \ { \ .length = _length, \ - .elem_type = __type_integer(_type, __BYTE_ORDER), \ + .elem_type = __type_integer(_type, __BYTE_ORDER, 10), \ }, \ }, \ }, @@ -115,8 +115,8 @@ void trace_##_name(_proto); .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), \ }, \ }, \ }, diff --git a/probes/lttng-ftrace.c b/probes/lttng-ftrace.c new file mode 100644 index 00000000..4b7be183 --- /dev/null +++ b/probes/lttng-ftrace.c @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2009-2011 - + * Mathieu Desnoyers + * + * LTTng function tracer integration module. + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#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"); diff --git a/probes/lttng-kprobes.c b/probes/lttng-kprobes.c index 1cffe685..9d9fb5b9 100644 --- a/probes/lttng-kprobes.c +++ b/probes/lttng-kprobes.c @@ -64,6 +64,8 @@ int lttng_create_kprobe_event(const char *name, struct ltt_event *event) 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; @@ -87,14 +89,14 @@ int lttng_kprobes_register(const char *name, 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; diff --git a/probes/lttng-types.h b/probes/lttng-types.h index c435b4d3..75853ee6 100644 --- a/probes/lttng-types.h +++ b/probes/lttng-types.h @@ -46,7 +46,7 @@ #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), \ }, -- 2.34.1