diff options
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 5 | ||||
-rw-r--r-- | include/linux/ftrace_event.h | 2 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 8 | ||||
-rw-r--r-- | include/trace/ftrace.h | 22 | ||||
-rw-r--r-- | kernel/trace/trace.c | 26 | ||||
-rw-r--r-- | kernel/trace/trace.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 119 |
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 | ||
39 | struct trace_enum_map { | ||
40 | const char *system; | ||
41 | const char *enum_string; | ||
42 | unsigned long enum_value; | ||
43 | }; | ||
44 | |||
39 | extern int | 45 | extern int |
40 | tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); | 46 | tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); |
41 | extern int | 47 | extern 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 | ||
34 | TRACE_MAKE_SYSTEM_STR(); | 34 | TRACE_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)); \ |
707 | static const char print_fmt_##call[] = print; \ | 723 | static char print_fmt_##call[] = print; \ |
708 | static struct ftrace_event_class __used __refdata event_class_##call = { \ | 724 | static 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 | \ |
736 | static const char print_fmt_##call[] = print; \ | 752 | static char print_fmt_##call[] = print; \ |
737 | \ | 753 | \ |
738 | static struct ftrace_event_call __used event_##call = { \ | 754 | static 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 | ||
3911 | static void | ||
3912 | trace_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 | |||
3911 | static ssize_t | 3925 | static ssize_t |
3912 | tracing_set_trace_read(struct file *filp, char __user *ubuf, | 3926 | tracing_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 | ||
6559 | extern struct trace_enum_map *__start_ftrace_enum_maps[]; | ||
6560 | extern struct trace_enum_map *__stop_ftrace_enum_maps[]; | ||
6561 | |||
6562 | static void __init trace_enum_init(void) | ||
6563 | { | ||
6564 | trace_insert_enum_map(__start_ftrace_enum_maps, __stop_ftrace_enum_maps); | ||
6565 | } | ||
6566 | |||
6545 | static __init int tracer_init_debugfs(void) | 6567 | static __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 |
1311 | void trace_event_init(void); | 1311 | void trace_event_init(void); |
1312 | void trace_event_enum_update(struct trace_enum_map **map, int len); | ||
1312 | #else | 1313 | #else |
1313 | static inline void __init trace_event_init(void) { } | 1314 | static inline void __init trace_event_init(void) { } |
1315 | static inlin void trace_event_enum_update(struct trace_enum_map **map, int len) { } | ||
1314 | #endif | 1316 | #endif |
1315 | 1317 | ||
1316 | extern struct trace_iterator *tracepoint_print_iter; | 1318 | extern 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 | ||
1707 | static 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 | |||
1729 | static 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 | |||
1799 | void 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 | |||
1707 | static struct ftrace_event_file * | 1826 | static struct ftrace_event_file * |
1708 | trace_create_new_event(struct ftrace_event_call *call, | 1827 | trace_create_new_event(struct ftrace_event_call *call, |
1709 | struct trace_array *tr) | 1828 | struct trace_array *tr) |