aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-generic/vmlinux.lds.h5
-rw-r--r--include/linux/ftrace_event.h2
-rw-r--r--include/linux/tracepoint.h8
-rw-r--r--include/trace/ftrace.h22
-rw-r--r--kernel/trace/trace.c26
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_events.c119
7 files changed, 178 insertions, 6 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index ac78910d7416..f8e8b34dc427 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -124,7 +124,10 @@
124#define FTRACE_EVENTS() . = ALIGN(8); \ 124#define FTRACE_EVENTS() . = ALIGN(8); \
125 VMLINUX_SYMBOL(__start_ftrace_events) = .; \ 125 VMLINUX_SYMBOL(__start_ftrace_events) = .; \
126 *(_ftrace_events) \ 126 *(_ftrace_events) \
127 VMLINUX_SYMBOL(__stop_ftrace_events) = .; 127 VMLINUX_SYMBOL(__stop_ftrace_events) = .; \
128 VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \
129 *(_ftrace_enum_map) \
130 VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
128#else 131#else
129#define FTRACE_EVENTS() 132#define FTRACE_EVENTS()
130#endif 133#endif
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 62b8fac7ded5..112cf49d9576 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -285,7 +285,7 @@ struct ftrace_event_call {
285 struct tracepoint *tp; 285 struct tracepoint *tp;
286 }; 286 };
287 struct trace_event event; 287 struct trace_event event;
288 const char *print_fmt; 288 char *print_fmt;
289 struct event_filter *filter; 289 struct event_filter *filter;
290 void *mod; 290 void *mod;
291 void *data; 291 void *data;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index c72851328ca9..a5f7f3ecafa3 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -36,6 +36,12 @@ struct tracepoint {
36 struct tracepoint_func __rcu *funcs; 36 struct tracepoint_func __rcu *funcs;
37}; 37};
38 38
39struct trace_enum_map {
40 const char *system;
41 const char *enum_string;
42 unsigned long enum_value;
43};
44
39extern int 45extern int
40tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); 46tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
41extern int 47extern int
@@ -87,6 +93,8 @@ extern void syscall_unregfunc(void);
87 93
88#define PARAMS(args...) args 94#define PARAMS(args...) args
89 95
96#define TRACE_DEFINE_ENUM(x)
97
90#endif /* _LINUX_TRACEPOINT_H */ 98#endif /* _LINUX_TRACEPOINT_H */
91 99
92/* 100/*
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 2f9b95b6d3fb..37d4b10b111d 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -33,6 +33,19 @@
33 33
34TRACE_MAKE_SYSTEM_STR(); 34TRACE_MAKE_SYSTEM_STR();
35 35
36#undef TRACE_DEFINE_ENUM
37#define TRACE_DEFINE_ENUM(a) \
38 static struct trace_enum_map __used __initdata \
39 __##TRACE_SYSTEM##_##a = \
40 { \
41 .system = TRACE_SYSTEM_STRING, \
42 .enum_string = #a, \
43 .enum_value = a \
44 }; \
45 static struct trace_enum_map __used \
46 __attribute__((section("_ftrace_enum_map"))) \
47 *TRACE_SYSTEM##_##a = &__##TRACE_SYSTEM##_##a
48
36/* 49/*
37 * DECLARE_EVENT_CLASS can be used to add a generic function 50 * DECLARE_EVENT_CLASS can be used to add a generic function
38 * handlers for events. That is, if all events have the same 51 * handlers for events. That is, if all events have the same
@@ -136,6 +149,9 @@ TRACE_MAKE_SYSTEM_STR();
136 * The size of an array is also encoded, in the higher 16 bits of <item>. 149 * The size of an array is also encoded, in the higher 16 bits of <item>.
137 */ 150 */
138 151
152#undef TRACE_DEFINE_ENUM
153#define TRACE_DEFINE_ENUM(a)
154
139#undef __field 155#undef __field
140#define __field(type, item) 156#define __field(type, item)
141 157
@@ -553,7 +569,7 @@ static inline notrace int ftrace_get_offsets_##call( \
553 * .trace = ftrace_raw_output_<call>, <-- stage 2 569 * .trace = ftrace_raw_output_<call>, <-- stage 2
554 * }; 570 * };
555 * 571 *
556 * static const char print_fmt_<call>[] = <TP_printk>; 572 * static char print_fmt_<call>[] = <TP_printk>;
557 * 573 *
558 * static struct ftrace_event_class __used event_class_<template> = { 574 * static struct ftrace_event_class __used event_class_<template> = {
559 * .system = "<system>", 575 * .system = "<system>",
@@ -704,7 +720,7 @@ static inline void ftrace_test_probe_##call(void) \
704#undef DECLARE_EVENT_CLASS 720#undef DECLARE_EVENT_CLASS
705#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ 721#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
706_TRACE_PERF_PROTO(call, PARAMS(proto)); \ 722_TRACE_PERF_PROTO(call, PARAMS(proto)); \
707static const char print_fmt_##call[] = print; \ 723static char print_fmt_##call[] = print; \
708static struct ftrace_event_class __used __refdata event_class_##call = { \ 724static struct ftrace_event_class __used __refdata event_class_##call = { \
709 .system = TRACE_SYSTEM_STRING, \ 725 .system = TRACE_SYSTEM_STRING, \
710 .define_fields = ftrace_define_fields_##call, \ 726 .define_fields = ftrace_define_fields_##call, \
@@ -733,7 +749,7 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
733#undef DEFINE_EVENT_PRINT 749#undef DEFINE_EVENT_PRINT
734#define DEFINE_EVENT_PRINT(template, call, proto, args, print) \ 750#define DEFINE_EVENT_PRINT(template, call, proto, args, print) \
735 \ 751 \
736static const char print_fmt_##call[] = print; \ 752static char print_fmt_##call[] = print; \
737 \ 753 \
738static struct ftrace_event_call __used event_##call = { \ 754static struct ftrace_event_call __used event_##call = { \
739 .class = &event_class_##template, \ 755 .class = &event_class_##template, \
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 62c6506d663f..ebf49649534c 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3908,6 +3908,20 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
3908 .write = tracing_saved_cmdlines_size_write, 3908 .write = tracing_saved_cmdlines_size_write,
3909}; 3909};
3910 3910
3911static void
3912trace_insert_enum_map(struct trace_enum_map **start, struct trace_enum_map **stop)
3913{
3914 struct trace_enum_map **map;
3915 int len = stop - start;
3916
3917 if (len <= 0)
3918 return;
3919
3920 map = start;
3921
3922 trace_event_enum_update(map, len);
3923}
3924
3911static ssize_t 3925static ssize_t
3912tracing_set_trace_read(struct file *filp, char __user *ubuf, 3926tracing_set_trace_read(struct file *filp, char __user *ubuf,
3913 size_t cnt, loff_t *ppos) 3927 size_t cnt, loff_t *ppos)
@@ -6542,6 +6556,14 @@ struct dentry *tracing_init_dentry(void)
6542 return tr->dir; 6556 return tr->dir;
6543} 6557}
6544 6558
6559extern struct trace_enum_map *__start_ftrace_enum_maps[];
6560extern struct trace_enum_map *__stop_ftrace_enum_maps[];
6561
6562static void __init trace_enum_init(void)
6563{
6564 trace_insert_enum_map(__start_ftrace_enum_maps, __stop_ftrace_enum_maps);
6565}
6566
6545static __init int tracer_init_debugfs(void) 6567static __init int tracer_init_debugfs(void)
6546{ 6568{
6547 struct dentry *d_tracer; 6569 struct dentry *d_tracer;
@@ -6566,6 +6588,8 @@ static __init int tracer_init_debugfs(void)
6566 trace_create_file("saved_cmdlines_size", 0644, d_tracer, 6588 trace_create_file("saved_cmdlines_size", 0644, d_tracer,
6567 NULL, &tracing_saved_cmdlines_size_fops); 6589 NULL, &tracing_saved_cmdlines_size_fops);
6568 6590
6591 trace_enum_init();
6592
6569#ifdef CONFIG_DYNAMIC_FTRACE 6593#ifdef CONFIG_DYNAMIC_FTRACE
6570 trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, 6594 trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
6571 &ftrace_update_tot_cnt, &tracing_dyn_info_fops); 6595 &ftrace_update_tot_cnt, &tracing_dyn_info_fops);
@@ -6888,7 +6912,7 @@ void __init trace_init(void)
6888 tracepoint_printk = 0; 6912 tracepoint_printk = 0;
6889 } 6913 }
6890 tracer_alloc_buffers(); 6914 tracer_alloc_buffers();
6891 trace_event_init(); 6915 trace_event_init();
6892} 6916}
6893 6917
6894__init static int clear_boot_tracer(void) 6918__init static int clear_boot_tracer(void)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index dd8205a35760..b48d4b08f691 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1309,8 +1309,10 @@ static inline void init_ftrace_syscalls(void) { }
1309 1309
1310#ifdef CONFIG_EVENT_TRACING 1310#ifdef CONFIG_EVENT_TRACING
1311void trace_event_init(void); 1311void trace_event_init(void);
1312void trace_event_enum_update(struct trace_enum_map **map, int len);
1312#else 1313#else
1313static inline void __init trace_event_init(void) { } 1314static inline void __init trace_event_init(void) { }
1315static inlin void trace_event_enum_update(struct trace_enum_map **map, int len) { }
1314#endif 1316#endif
1315 1317
1316extern struct trace_iterator *tracepoint_print_iter; 1318extern struct trace_iterator *tracepoint_print_iter;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index db54dda10ccc..fc58c50fbf01 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1704,6 +1704,125 @@ __register_event(struct ftrace_event_call *call, struct module *mod)
1704 return 0; 1704 return 0;
1705} 1705}
1706 1706
1707static char *enum_replace(char *ptr, struct trace_enum_map *map, int len)
1708{
1709 int rlen;
1710 int elen;
1711
1712 /* Find the length of the enum value as a string */
1713 elen = snprintf(ptr, 0, "%ld", map->enum_value);
1714 /* Make sure there's enough room to replace the string with the value */
1715 if (len < elen)
1716 return NULL;
1717
1718 snprintf(ptr, elen + 1, "%ld", map->enum_value);
1719
1720 /* Get the rest of the string of ptr */
1721 rlen = strlen(ptr + len);
1722 memmove(ptr + elen, ptr + len, rlen);
1723 /* Make sure we end the new string */
1724 ptr[elen + rlen] = 0;
1725
1726 return ptr + elen;
1727}
1728
1729static void update_event_printk(struct ftrace_event_call *call,
1730 struct trace_enum_map *map)
1731{
1732 char *ptr;
1733 int quote = 0;
1734 int len = strlen(map->enum_string);
1735
1736 for (ptr = call->print_fmt; *ptr; ptr++) {
1737 if (*ptr == '\\') {
1738 ptr++;
1739 /* paranoid */
1740 if (!*ptr)
1741 break;
1742 continue;
1743 }
1744 if (*ptr == '"') {
1745 quote ^= 1;
1746 continue;
1747 }
1748 if (quote)
1749 continue;
1750 if (isdigit(*ptr)) {
1751 /* skip numbers */
1752 do {
1753 ptr++;
1754 /* Check for alpha chars like ULL */
1755 } while (isalnum(*ptr));
1756 /*
1757 * A number must have some kind of delimiter after
1758 * it, and we can ignore that too.
1759 */
1760 continue;
1761 }
1762 if (isalpha(*ptr) || *ptr == '_') {
1763 if (strncmp(map->enum_string, ptr, len) == 0 &&
1764 !isalnum(ptr[len]) && ptr[len] != '_') {
1765 ptr = enum_replace(ptr, map, len);
1766 /* Hmm, enum string smaller than value */
1767 if (WARN_ON_ONCE(!ptr))
1768 return;
1769 /*
1770 * No need to decrement here, as enum_replace()
1771 * returns the pointer to the character passed
1772 * the enum, and two enums can not be placed
1773 * back to back without something in between.
1774 * We can skip that something in between.
1775 */
1776 continue;
1777 }
1778 skip_more:
1779 do {
1780 ptr++;
1781 } while (isalnum(*ptr) || *ptr == '_');
1782 /*
1783 * If what comes after this variable is a '.' or
1784 * '->' then we can continue to ignore that string.
1785 */
1786 if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
1787 ptr += *ptr == '.' ? 1 : 2;
1788 goto skip_more;
1789 }
1790 /*
1791 * Once again, we can skip the delimiter that came
1792 * after the string.
1793 */
1794 continue;
1795 }
1796 }
1797}
1798
1799void trace_event_enum_update(struct trace_enum_map **map, int len)
1800{
1801 struct ftrace_event_call *call, *p;
1802 const char *last_system = NULL;
1803 int last_i;
1804 int i;
1805
1806 down_write(&trace_event_sem);
1807 list_for_each_entry_safe(call, p, &ftrace_events, list) {
1808 /* events are usually grouped together with systems */
1809 if (!last_system || call->class->system != last_system) {
1810 last_i = 0;
1811 last_system = call->class->system;
1812 }
1813
1814 for (i = last_i; i < len; i++) {
1815 if (call->class->system == map[i]->system) {
1816 /* Save the first system if need be */
1817 if (!last_i)
1818 last_i = i;
1819 update_event_printk(call, map[i]);
1820 }
1821 }
1822 }
1823 up_write(&trace_event_sem);
1824}
1825
1707static struct ftrace_event_file * 1826static struct ftrace_event_file *
1708trace_create_new_event(struct ftrace_event_call *call, 1827trace_create_new_event(struct ftrace_event_call *call,
1709 struct trace_array *tr) 1828 struct trace_array *tr)