Function tracer support
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 19 May 2011 03:46:54 +0000 (23:46 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 19 May 2011 03:46:54 +0000 (23:46 -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-events.h
probes/lttng-ftrace.c [new file with mode: 0644]
probes/lttng-kprobes.c
probes/lttng-types.h

index 9139e5a1751f8ba56ea48c2676d6480d8c08a779..a889378f95ae8f22403558ab713857c9cfb3c585 100644 (file)
@@ -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;
index 411c37b78ff0d0f88787c20420f7337ab1db27f9..74ad764da2bdf9ab4d5685c0f8fccb8bedb710ea 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/fs.h>
 
-#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 {
index cf4fc8b77158fb0f0c398d49249dacce16511ad4..20db4c55bdc75703a8fad2b7016a38887ae768c1 100644 (file)
@@ -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 ?
index 030ffe02356189b792ebb7b41850eeb115043e54..e10c66c8f2d92460b8e3684107554e68a9486995 100644 (file)
@@ -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 */
index 77ff09a2e99288156a52d1d8ee7a26bb673e30a5..14a7c93bc3c867a361aae0d10a3711d36ae10b18 100644 (file)
@@ -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
index 5ee61bc612472bb49e5e8b12915da50a319e96b1..8ffc23a28034d96cab6cd632d9a408ef71a878f9 100644 (file)
@@ -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 (file)
index 0000000..4b7be18
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * (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,
+                       &lttng_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,
+                       &lttng_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");
index 1cffe685bd834f7738020e4f36a4c13e7127245c..9d9fb5b9a759fd6445f70478c907657736f1f082 100644 (file)
@@ -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;
index c435b4d3ea127346e3b21c31bb115ab2bc3896a6..75853ee63319ccd28e0eb41ec9182a4ae9517b2a 100644 (file)
@@ -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), \
                },
This page took 0.034154 seconds and 4 git commands to generate.