diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/Kconfig | 2 | ||||
-rw-r--r-- | kernel/trace/Makefile | 2 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 17 | ||||
-rw-r--r-- | kernel/trace/ring_buffer.c | 2 | ||||
-rw-r--r-- | kernel/trace/trace.c | 165 | ||||
-rw-r--r-- | kernel/trace/trace.h | 15 | ||||
-rw-r--r-- | kernel/trace/trace_event_types.h | 165 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 12 | ||||
-rw-r--r-- | kernel/trace/trace_events_stage_2.h | 53 | ||||
-rw-r--r-- | kernel/trace/trace_export.c | 81 | ||||
-rw-r--r-- | kernel/trace/trace_format.h | 55 | ||||
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 6 | ||||
-rw-r--r-- | kernel/trace/trace_mmiotrace.c | 9 | ||||
-rw-r--r-- | kernel/trace/trace_output.c | 41 | ||||
-rw-r--r-- | kernel/trace/trace_output.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_printk.c | 138 | ||||
-rw-r--r-- | kernel/trace/trace_sysprof.c | 2 |
17 files changed, 589 insertions, 178 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 5d733da5345a..8e4a2a61cd75 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -52,6 +52,7 @@ config TRACING | |||
52 | select STACKTRACE if STACKTRACE_SUPPORT | 52 | select STACKTRACE if STACKTRACE_SUPPORT |
53 | select TRACEPOINTS | 53 | select TRACEPOINTS |
54 | select NOP_TRACER | 54 | select NOP_TRACER |
55 | select BINARY_PRINTF | ||
55 | 56 | ||
56 | # | 57 | # |
57 | # Minimum requirements an architecture has to meet for us to | 58 | # Minimum requirements an architecture has to meet for us to |
@@ -61,6 +62,7 @@ config TRACING_SUPPORT | |||
61 | bool | 62 | bool |
62 | depends on TRACE_IRQFLAGS_SUPPORT | 63 | depends on TRACE_IRQFLAGS_SUPPORT |
63 | depends on STACKTRACE_SUPPORT | 64 | depends on STACKTRACE_SUPPORT |
65 | default y | ||
64 | 66 | ||
65 | if TRACING_SUPPORT | 67 | if TRACING_SUPPORT |
66 | 68 | ||
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index c931fe0560cb..c7a2943796eb 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_TRACING) += trace.o | |||
22 | obj-$(CONFIG_TRACING) += trace_clock.o | 22 | obj-$(CONFIG_TRACING) += trace_clock.o |
23 | obj-$(CONFIG_TRACING) += trace_output.o | 23 | obj-$(CONFIG_TRACING) += trace_output.o |
24 | obj-$(CONFIG_TRACING) += trace_stat.o | 24 | obj-$(CONFIG_TRACING) += trace_stat.o |
25 | obj-$(CONFIG_TRACING) += trace_printk.o | ||
25 | obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o | 26 | obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o |
26 | obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o | 27 | obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o |
27 | obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o | 28 | obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o |
@@ -41,5 +42,6 @@ obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o | |||
41 | obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o | 42 | obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o |
42 | obj-$(CONFIG_EVENT_TRACER) += trace_events.o | 43 | obj-$(CONFIG_EVENT_TRACER) += trace_events.o |
43 | obj-$(CONFIG_EVENT_TRACER) += events.o | 44 | obj-$(CONFIG_EVENT_TRACER) += events.o |
45 | obj-$(CONFIG_EVENT_TRACER) += trace_export.o | ||
44 | 46 | ||
45 | libftrace-y := ftrace.o | 47 | libftrace-y := ftrace.o |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5a3a06b21eee..d33d306bdcf4 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -218,10 +218,8 @@ static void ftrace_update_pid_func(void) | |||
218 | { | 218 | { |
219 | ftrace_func_t func; | 219 | ftrace_func_t func; |
220 | 220 | ||
221 | mutex_lock(&ftrace_lock); | ||
222 | |||
223 | if (ftrace_trace_function == ftrace_stub) | 221 | if (ftrace_trace_function == ftrace_stub) |
224 | goto out; | 222 | return; |
225 | 223 | ||
226 | func = ftrace_trace_function; | 224 | func = ftrace_trace_function; |
227 | 225 | ||
@@ -238,9 +236,6 @@ static void ftrace_update_pid_func(void) | |||
238 | #else | 236 | #else |
239 | __ftrace_trace_function = func; | 237 | __ftrace_trace_function = func; |
240 | #endif | 238 | #endif |
241 | |||
242 | out: | ||
243 | mutex_unlock(&ftrace_lock); | ||
244 | } | 239 | } |
245 | 240 | ||
246 | /* set when tracing only a pid */ | 241 | /* set when tracing only a pid */ |
@@ -1869,21 +1864,21 @@ ftrace_notrace_release(struct inode *inode, struct file *file) | |||
1869 | return ftrace_regex_release(inode, file, 0); | 1864 | return ftrace_regex_release(inode, file, 0); |
1870 | } | 1865 | } |
1871 | 1866 | ||
1872 | static struct file_operations ftrace_avail_fops = { | 1867 | static const struct file_operations ftrace_avail_fops = { |
1873 | .open = ftrace_avail_open, | 1868 | .open = ftrace_avail_open, |
1874 | .read = seq_read, | 1869 | .read = seq_read, |
1875 | .llseek = seq_lseek, | 1870 | .llseek = seq_lseek, |
1876 | .release = ftrace_avail_release, | 1871 | .release = ftrace_avail_release, |
1877 | }; | 1872 | }; |
1878 | 1873 | ||
1879 | static struct file_operations ftrace_failures_fops = { | 1874 | static const struct file_operations ftrace_failures_fops = { |
1880 | .open = ftrace_failures_open, | 1875 | .open = ftrace_failures_open, |
1881 | .read = seq_read, | 1876 | .read = seq_read, |
1882 | .llseek = seq_lseek, | 1877 | .llseek = seq_lseek, |
1883 | .release = ftrace_avail_release, | 1878 | .release = ftrace_avail_release, |
1884 | }; | 1879 | }; |
1885 | 1880 | ||
1886 | static struct file_operations ftrace_filter_fops = { | 1881 | static const struct file_operations ftrace_filter_fops = { |
1887 | .open = ftrace_filter_open, | 1882 | .open = ftrace_filter_open, |
1888 | .read = ftrace_regex_read, | 1883 | .read = ftrace_regex_read, |
1889 | .write = ftrace_filter_write, | 1884 | .write = ftrace_filter_write, |
@@ -1891,7 +1886,7 @@ static struct file_operations ftrace_filter_fops = { | |||
1891 | .release = ftrace_filter_release, | 1886 | .release = ftrace_filter_release, |
1892 | }; | 1887 | }; |
1893 | 1888 | ||
1894 | static struct file_operations ftrace_notrace_fops = { | 1889 | static const struct file_operations ftrace_notrace_fops = { |
1895 | .open = ftrace_notrace_open, | 1890 | .open = ftrace_notrace_open, |
1896 | .read = ftrace_regex_read, | 1891 | .read = ftrace_regex_read, |
1897 | .write = ftrace_notrace_write, | 1892 | .write = ftrace_notrace_write, |
@@ -2423,7 +2418,7 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf, | |||
2423 | return cnt; | 2418 | return cnt; |
2424 | } | 2419 | } |
2425 | 2420 | ||
2426 | static struct file_operations ftrace_pid_fops = { | 2421 | static const struct file_operations ftrace_pid_fops = { |
2427 | .read = ftrace_pid_read, | 2422 | .read = ftrace_pid_read, |
2428 | .write = ftrace_pid_write, | 2423 | .write = ftrace_pid_write, |
2429 | }; | 2424 | }; |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index f7473645b9c6..178858492a89 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -2606,7 +2606,7 @@ rb_simple_write(struct file *filp, const char __user *ubuf, | |||
2606 | return cnt; | 2606 | return cnt; |
2607 | } | 2607 | } |
2608 | 2608 | ||
2609 | static struct file_operations rb_simple_fops = { | 2609 | static const struct file_operations rb_simple_fops = { |
2610 | .open = tracing_open_generic, | 2610 | .open = tracing_open_generic, |
2611 | .read = rb_simple_read, | 2611 | .read = rb_simple_read, |
2612 | .write = rb_simple_write, | 2612 | .write = rb_simple_write, |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c0e9c1263393..cc94f8642485 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -1169,6 +1169,67 @@ void trace_graph_return(struct ftrace_graph_ret *trace) | |||
1169 | } | 1169 | } |
1170 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 1170 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
1171 | 1171 | ||
1172 | |||
1173 | /** | ||
1174 | * trace_vprintk - write binary msg to tracing buffer | ||
1175 | * | ||
1176 | */ | ||
1177 | int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args) | ||
1178 | { | ||
1179 | static DEFINE_SPINLOCK(trace_buf_lock); | ||
1180 | static u32 trace_buf[TRACE_BUF_SIZE]; | ||
1181 | |||
1182 | struct ring_buffer_event *event; | ||
1183 | struct trace_array *tr = &global_trace; | ||
1184 | struct trace_array_cpu *data; | ||
1185 | struct print_entry *entry; | ||
1186 | unsigned long flags; | ||
1187 | int resched; | ||
1188 | int cpu, len = 0, size, pc; | ||
1189 | |||
1190 | if (unlikely(tracing_selftest_running || tracing_disabled)) | ||
1191 | return 0; | ||
1192 | |||
1193 | /* Don't pollute graph traces with trace_vprintk internals */ | ||
1194 | pause_graph_tracing(); | ||
1195 | |||
1196 | pc = preempt_count(); | ||
1197 | resched = ftrace_preempt_disable(); | ||
1198 | cpu = raw_smp_processor_id(); | ||
1199 | data = tr->data[cpu]; | ||
1200 | |||
1201 | if (unlikely(atomic_read(&data->disabled))) | ||
1202 | goto out; | ||
1203 | |||
1204 | spin_lock_irqsave(&trace_buf_lock, flags); | ||
1205 | len = vbin_printf(trace_buf, TRACE_BUF_SIZE, fmt, args); | ||
1206 | |||
1207 | if (len > TRACE_BUF_SIZE || len < 0) | ||
1208 | goto out_unlock; | ||
1209 | |||
1210 | size = sizeof(*entry) + sizeof(u32) * len; | ||
1211 | event = trace_buffer_lock_reserve(tr, TRACE_PRINT, size, flags, pc); | ||
1212 | if (!event) | ||
1213 | goto out_unlock; | ||
1214 | entry = ring_buffer_event_data(event); | ||
1215 | entry->ip = ip; | ||
1216 | entry->depth = depth; | ||
1217 | entry->fmt = fmt; | ||
1218 | |||
1219 | memcpy(entry->buf, trace_buf, sizeof(u32) * len); | ||
1220 | ring_buffer_unlock_commit(tr->buffer, event); | ||
1221 | |||
1222 | out_unlock: | ||
1223 | spin_unlock_irqrestore(&trace_buf_lock, flags); | ||
1224 | |||
1225 | out: | ||
1226 | ftrace_preempt_enable(resched); | ||
1227 | unpause_graph_tracing(); | ||
1228 | |||
1229 | return len; | ||
1230 | } | ||
1231 | EXPORT_SYMBOL_GPL(trace_vprintk); | ||
1232 | |||
1172 | enum trace_file_type { | 1233 | enum trace_file_type { |
1173 | TRACE_FILE_LAT_FMT = 1, | 1234 | TRACE_FILE_LAT_FMT = 1, |
1174 | TRACE_FILE_ANNOTATE = 2, | 1235 | TRACE_FILE_ANNOTATE = 2, |
@@ -1564,7 +1625,7 @@ static enum print_line_t print_printk_msg_only(struct trace_iterator *iter) | |||
1564 | 1625 | ||
1565 | trace_assign_type(field, entry); | 1626 | trace_assign_type(field, entry); |
1566 | 1627 | ||
1567 | ret = trace_seq_printf(s, "%s", field->buf); | 1628 | ret = trace_seq_bprintf(s, field->fmt, field->buf); |
1568 | if (!ret) | 1629 | if (!ret) |
1569 | return TRACE_TYPE_PARTIAL_LINE; | 1630 | return TRACE_TYPE_PARTIAL_LINE; |
1570 | 1631 | ||
@@ -1882,14 +1943,14 @@ static int show_traces_open(struct inode *inode, struct file *file) | |||
1882 | return ret; | 1943 | return ret; |
1883 | } | 1944 | } |
1884 | 1945 | ||
1885 | static struct file_operations tracing_fops = { | 1946 | static const struct file_operations tracing_fops = { |
1886 | .open = tracing_open, | 1947 | .open = tracing_open, |
1887 | .read = seq_read, | 1948 | .read = seq_read, |
1888 | .llseek = seq_lseek, | 1949 | .llseek = seq_lseek, |
1889 | .release = tracing_release, | 1950 | .release = tracing_release, |
1890 | }; | 1951 | }; |
1891 | 1952 | ||
1892 | static struct file_operations show_traces_fops = { | 1953 | static const struct file_operations show_traces_fops = { |
1893 | .open = show_traces_open, | 1954 | .open = show_traces_open, |
1894 | .read = seq_read, | 1955 | .read = seq_read, |
1895 | .release = seq_release, | 1956 | .release = seq_release, |
@@ -1982,7 +2043,7 @@ err_unlock: | |||
1982 | return err; | 2043 | return err; |
1983 | } | 2044 | } |
1984 | 2045 | ||
1985 | static struct file_operations tracing_cpumask_fops = { | 2046 | static const struct file_operations tracing_cpumask_fops = { |
1986 | .open = tracing_open_generic, | 2047 | .open = tracing_open_generic, |
1987 | .read = tracing_cpumask_read, | 2048 | .read = tracing_cpumask_read, |
1988 | .write = tracing_cpumask_write, | 2049 | .write = tracing_cpumask_write, |
@@ -2134,7 +2195,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf, | |||
2134 | return cnt; | 2195 | return cnt; |
2135 | } | 2196 | } |
2136 | 2197 | ||
2137 | static struct file_operations tracing_iter_fops = { | 2198 | static const struct file_operations tracing_iter_fops = { |
2138 | .open = tracing_open_generic, | 2199 | .open = tracing_open_generic, |
2139 | .read = tracing_trace_options_read, | 2200 | .read = tracing_trace_options_read, |
2140 | .write = tracing_trace_options_write, | 2201 | .write = tracing_trace_options_write, |
@@ -2167,7 +2228,7 @@ tracing_readme_read(struct file *filp, char __user *ubuf, | |||
2167 | readme_msg, strlen(readme_msg)); | 2228 | readme_msg, strlen(readme_msg)); |
2168 | } | 2229 | } |
2169 | 2230 | ||
2170 | static struct file_operations tracing_readme_fops = { | 2231 | static const struct file_operations tracing_readme_fops = { |
2171 | .open = tracing_open_generic, | 2232 | .open = tracing_open_generic, |
2172 | .read = tracing_readme_read, | 2233 | .read = tracing_readme_read, |
2173 | }; | 2234 | }; |
@@ -2927,25 +2988,25 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
2927 | return cnt; | 2988 | return cnt; |
2928 | } | 2989 | } |
2929 | 2990 | ||
2930 | static struct file_operations tracing_max_lat_fops = { | 2991 | static const struct file_operations tracing_max_lat_fops = { |
2931 | .open = tracing_open_generic, | 2992 | .open = tracing_open_generic, |
2932 | .read = tracing_max_lat_read, | 2993 | .read = tracing_max_lat_read, |
2933 | .write = tracing_max_lat_write, | 2994 | .write = tracing_max_lat_write, |
2934 | }; | 2995 | }; |
2935 | 2996 | ||
2936 | static struct file_operations tracing_ctrl_fops = { | 2997 | static const struct file_operations tracing_ctrl_fops = { |
2937 | .open = tracing_open_generic, | 2998 | .open = tracing_open_generic, |
2938 | .read = tracing_ctrl_read, | 2999 | .read = tracing_ctrl_read, |
2939 | .write = tracing_ctrl_write, | 3000 | .write = tracing_ctrl_write, |
2940 | }; | 3001 | }; |
2941 | 3002 | ||
2942 | static struct file_operations set_tracer_fops = { | 3003 | static const struct file_operations set_tracer_fops = { |
2943 | .open = tracing_open_generic, | 3004 | .open = tracing_open_generic, |
2944 | .read = tracing_set_trace_read, | 3005 | .read = tracing_set_trace_read, |
2945 | .write = tracing_set_trace_write, | 3006 | .write = tracing_set_trace_write, |
2946 | }; | 3007 | }; |
2947 | 3008 | ||
2948 | static struct file_operations tracing_pipe_fops = { | 3009 | static const struct file_operations tracing_pipe_fops = { |
2949 | .open = tracing_open_pipe, | 3010 | .open = tracing_open_pipe, |
2950 | .poll = tracing_poll_pipe, | 3011 | .poll = tracing_poll_pipe, |
2951 | .read = tracing_read_pipe, | 3012 | .read = tracing_read_pipe, |
@@ -2953,13 +3014,13 @@ static struct file_operations tracing_pipe_fops = { | |||
2953 | .release = tracing_release_pipe, | 3014 | .release = tracing_release_pipe, |
2954 | }; | 3015 | }; |
2955 | 3016 | ||
2956 | static struct file_operations tracing_entries_fops = { | 3017 | static const struct file_operations tracing_entries_fops = { |
2957 | .open = tracing_open_generic, | 3018 | .open = tracing_open_generic, |
2958 | .read = tracing_entries_read, | 3019 | .read = tracing_entries_read, |
2959 | .write = tracing_entries_write, | 3020 | .write = tracing_entries_write, |
2960 | }; | 3021 | }; |
2961 | 3022 | ||
2962 | static struct file_operations tracing_mark_fops = { | 3023 | static const struct file_operations tracing_mark_fops = { |
2963 | .open = tracing_open_generic, | 3024 | .open = tracing_open_generic, |
2964 | .write = tracing_mark_write, | 3025 | .write = tracing_mark_write, |
2965 | }; | 3026 | }; |
@@ -3240,7 +3301,7 @@ tracing_read_dyn_info(struct file *filp, char __user *ubuf, | |||
3240 | return r; | 3301 | return r; |
3241 | } | 3302 | } |
3242 | 3303 | ||
3243 | static struct file_operations tracing_dyn_info_fops = { | 3304 | static const struct file_operations tracing_dyn_info_fops = { |
3244 | .open = tracing_open_generic, | 3305 | .open = tracing_open_generic, |
3245 | .read = tracing_read_dyn_info, | 3306 | .read = tracing_read_dyn_info, |
3246 | }; | 3307 | }; |
@@ -3714,84 +3775,6 @@ static __init int tracer_init_debugfs(void) | |||
3714 | return 0; | 3775 | return 0; |
3715 | } | 3776 | } |
3716 | 3777 | ||
3717 | int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args) | ||
3718 | { | ||
3719 | static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
3720 | static char trace_buf[TRACE_BUF_SIZE]; | ||
3721 | |||
3722 | struct ring_buffer_event *event; | ||
3723 | struct trace_array *tr = &global_trace; | ||
3724 | struct trace_array_cpu *data; | ||
3725 | int cpu, len = 0, size, pc; | ||
3726 | struct print_entry *entry; | ||
3727 | unsigned long irq_flags; | ||
3728 | |||
3729 | if (tracing_disabled || tracing_selftest_running) | ||
3730 | return 0; | ||
3731 | |||
3732 | pc = preempt_count(); | ||
3733 | preempt_disable_notrace(); | ||
3734 | cpu = raw_smp_processor_id(); | ||
3735 | data = tr->data[cpu]; | ||
3736 | |||
3737 | if (unlikely(atomic_read(&data->disabled))) | ||
3738 | goto out; | ||
3739 | |||
3740 | pause_graph_tracing(); | ||
3741 | raw_local_irq_save(irq_flags); | ||
3742 | __raw_spin_lock(&trace_buf_lock); | ||
3743 | len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args); | ||
3744 | |||
3745 | len = min(len, TRACE_BUF_SIZE-1); | ||
3746 | trace_buf[len] = 0; | ||
3747 | |||
3748 | size = sizeof(*entry) + len + 1; | ||
3749 | event = trace_buffer_lock_reserve(tr, TRACE_PRINT, size, irq_flags, pc); | ||
3750 | if (!event) | ||
3751 | goto out_unlock; | ||
3752 | entry = ring_buffer_event_data(event); | ||
3753 | entry->ip = ip; | ||
3754 | entry->depth = depth; | ||
3755 | |||
3756 | memcpy(&entry->buf, trace_buf, len); | ||
3757 | entry->buf[len] = 0; | ||
3758 | ring_buffer_unlock_commit(tr->buffer, event); | ||
3759 | |||
3760 | out_unlock: | ||
3761 | __raw_spin_unlock(&trace_buf_lock); | ||
3762 | raw_local_irq_restore(irq_flags); | ||
3763 | unpause_graph_tracing(); | ||
3764 | out: | ||
3765 | preempt_enable_notrace(); | ||
3766 | |||
3767 | return len; | ||
3768 | } | ||
3769 | EXPORT_SYMBOL_GPL(trace_vprintk); | ||
3770 | |||
3771 | int __trace_printk(unsigned long ip, const char *fmt, ...) | ||
3772 | { | ||
3773 | int ret; | ||
3774 | va_list ap; | ||
3775 | |||
3776 | if (!(trace_flags & TRACE_ITER_PRINTK)) | ||
3777 | return 0; | ||
3778 | |||
3779 | va_start(ap, fmt); | ||
3780 | ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); | ||
3781 | va_end(ap); | ||
3782 | return ret; | ||
3783 | } | ||
3784 | EXPORT_SYMBOL_GPL(__trace_printk); | ||
3785 | |||
3786 | int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) | ||
3787 | { | ||
3788 | if (!(trace_flags & TRACE_ITER_PRINTK)) | ||
3789 | return 0; | ||
3790 | |||
3791 | return trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); | ||
3792 | } | ||
3793 | EXPORT_SYMBOL_GPL(__ftrace_vprintk); | ||
3794 | |||
3795 | static int trace_panic_handler(struct notifier_block *this, | 3778 | static int trace_panic_handler(struct notifier_block *this, |
3796 | unsigned long event, void *unused) | 3779 | unsigned long event, void *unused) |
3797 | { | 3780 | { |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 8beff03fda68..2bfb7d11fc17 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -121,7 +121,8 @@ struct print_entry { | |||
121 | struct trace_entry ent; | 121 | struct trace_entry ent; |
122 | unsigned long ip; | 122 | unsigned long ip; |
123 | int depth; | 123 | int depth; |
124 | char buf[]; | 124 | const char *fmt; |
125 | u32 buf[]; | ||
125 | }; | 126 | }; |
126 | 127 | ||
127 | #define TRACE_OLD_SIZE 88 | 128 | #define TRACE_OLD_SIZE 88 |
@@ -195,7 +196,7 @@ struct kmemtrace_free_entry { | |||
195 | * trace_flag_type is an enumeration that holds different | 196 | * trace_flag_type is an enumeration that holds different |
196 | * states when a trace occurs. These are: | 197 | * states when a trace occurs. These are: |
197 | * IRQS_OFF - interrupts were disabled | 198 | * IRQS_OFF - interrupts were disabled |
198 | * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags | 199 | * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags |
199 | * NEED_RESCED - reschedule is requested | 200 | * NEED_RESCED - reschedule is requested |
200 | * HARDIRQ - inside an interrupt handler | 201 | * HARDIRQ - inside an interrupt handler |
201 | * SOFTIRQ - inside a softirq handler | 202 | * SOFTIRQ - inside a softirq handler |
@@ -298,7 +299,7 @@ extern void __ftrace_bad_type(void); | |||
298 | IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \ | 299 | IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \ |
299 | TRACE_GRAPH_RET); \ | 300 | TRACE_GRAPH_RET); \ |
300 | IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\ | 301 | IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\ |
301 | IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \ | 302 | IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \ |
302 | IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \ | 303 | IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \ |
303 | TRACE_KMEM_ALLOC); \ | 304 | TRACE_KMEM_ALLOC); \ |
304 | IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ | 305 | IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ |
@@ -321,8 +322,8 @@ enum print_line_t { | |||
321 | * flags value in struct tracer_flags. | 322 | * flags value in struct tracer_flags. |
322 | */ | 323 | */ |
323 | struct tracer_opt { | 324 | struct tracer_opt { |
324 | const char *name; /* Will appear on the trace_options file */ | 325 | const char *name; /* Will appear on the trace_options file */ |
325 | u32 bit; /* Mask assigned in val field in tracer_flags */ | 326 | u32 bit; /* Mask assigned in val field in tracer_flags */ |
326 | }; | 327 | }; |
327 | 328 | ||
328 | /* | 329 | /* |
@@ -331,7 +332,7 @@ struct tracer_opt { | |||
331 | */ | 332 | */ |
332 | struct tracer_flags { | 333 | struct tracer_flags { |
333 | u32 val; | 334 | u32 val; |
334 | struct tracer_opt *opts; | 335 | struct tracer_opt *opts; |
335 | }; | 336 | }; |
336 | 337 | ||
337 | /* Makes more easy to define a tracer opt */ | 338 | /* Makes more easy to define a tracer opt */ |
@@ -386,7 +387,7 @@ struct tracer { | |||
386 | int (*set_flag)(u32 old_flags, u32 bit, int set); | 387 | int (*set_flag)(u32 old_flags, u32 bit, int set); |
387 | struct tracer *next; | 388 | struct tracer *next; |
388 | int print_max; | 389 | int print_max; |
389 | struct tracer_flags *flags; | 390 | struct tracer_flags *flags; |
390 | struct tracer_stat *stats; | 391 | struct tracer_stat *stats; |
391 | }; | 392 | }; |
392 | 393 | ||
diff --git a/kernel/trace/trace_event_types.h b/kernel/trace/trace_event_types.h new file mode 100644 index 000000000000..fb4eba166433 --- /dev/null +++ b/kernel/trace/trace_event_types.h | |||
@@ -0,0 +1,165 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM ftrace | ||
3 | |||
4 | /* | ||
5 | * We cheat and use the proto type field as the ID | ||
6 | * and args as the entry type (minus 'struct') | ||
7 | */ | ||
8 | TRACE_EVENT_FORMAT(function, TRACE_FN, ftrace_entry, ignore, | ||
9 | TRACE_STRUCT( | ||
10 | TRACE_FIELD(unsigned long, ip, ip) | ||
11 | TRACE_FIELD(unsigned long, parent_ip, parent_ip) | ||
12 | ), | ||
13 | TPRAWFMT(" %lx <-- %lx") | ||
14 | ); | ||
15 | |||
16 | TRACE_EVENT_FORMAT(funcgraph_entry, TRACE_GRAPH_ENT, | ||
17 | ftrace_graph_ent_entry, ignore, | ||
18 | TRACE_STRUCT( | ||
19 | TRACE_FIELD(unsigned long, graph_ent.func, func) | ||
20 | TRACE_FIELD(int, graph_ent.depth, depth) | ||
21 | ), | ||
22 | TPRAWFMT("--> %lx (%d)") | ||
23 | ); | ||
24 | |||
25 | TRACE_EVENT_FORMAT(funcgraph_exit, TRACE_GRAPH_RET, | ||
26 | ftrace_graph_ret_entry, ignore, | ||
27 | TRACE_STRUCT( | ||
28 | TRACE_FIELD(unsigned long, ret.func, func) | ||
29 | TRACE_FIELD(int, ret.depth, depth) | ||
30 | ), | ||
31 | TPRAWFMT("<-- %lx (%d)") | ||
32 | ); | ||
33 | |||
34 | TRACE_EVENT_FORMAT(wakeup, TRACE_WAKE, ctx_switch_entry, ignore, | ||
35 | TRACE_STRUCT( | ||
36 | TRACE_FIELD(unsigned int, prev_pid, prev_pid) | ||
37 | TRACE_FIELD(unsigned char, prev_prio, prev_prio) | ||
38 | TRACE_FIELD(unsigned char, prev_state, prev_state) | ||
39 | TRACE_FIELD(unsigned int, next_pid, next_pid) | ||
40 | TRACE_FIELD(unsigned char, next_prio, next_prio) | ||
41 | TRACE_FIELD(unsigned char, next_state, next_state) | ||
42 | TRACE_FIELD(unsigned int, next_cpu, next_cpu) | ||
43 | ), | ||
44 | TPRAWFMT("%u:%u:%u ==+ %u:%u:%u [%03u]") | ||
45 | ); | ||
46 | |||
47 | TRACE_EVENT_FORMAT(context_switch, TRACE_CTX, ctx_switch_entry, ignore, | ||
48 | TRACE_STRUCT( | ||
49 | TRACE_FIELD(unsigned int, prev_pid, prev_pid) | ||
50 | TRACE_FIELD(unsigned char, prev_prio, prev_prio) | ||
51 | TRACE_FIELD(unsigned char, prev_state, prev_state) | ||
52 | TRACE_FIELD(unsigned int, next_pid, next_pid) | ||
53 | TRACE_FIELD(unsigned char, next_prio, next_prio) | ||
54 | TRACE_FIELD(unsigned char, next_state, next_state) | ||
55 | TRACE_FIELD(unsigned int, next_cpu, next_cpu) | ||
56 | ), | ||
57 | TPRAWFMT("%u:%u:%u ==+ %u:%u:%u [%03u]") | ||
58 | ); | ||
59 | |||
60 | TRACE_EVENT_FORMAT(special, TRACE_SPECIAL, special_entry, ignore, | ||
61 | TRACE_STRUCT( | ||
62 | TRACE_FIELD(unsigned long, arg1, arg1) | ||
63 | TRACE_FIELD(unsigned long, arg2, arg2) | ||
64 | TRACE_FIELD(unsigned long, arg3, arg3) | ||
65 | ), | ||
66 | TPRAWFMT("(%08lx) (%08lx) (%08lx)") | ||
67 | ); | ||
68 | |||
69 | /* | ||
70 | * Stack-trace entry: | ||
71 | */ | ||
72 | |||
73 | /* #define FTRACE_STACK_ENTRIES 8 */ | ||
74 | |||
75 | TRACE_EVENT_FORMAT(kernel_stack, TRACE_STACK, stack_entry, ignore, | ||
76 | TRACE_STRUCT( | ||
77 | TRACE_FIELD(unsigned long, caller[0], stack0) | ||
78 | TRACE_FIELD(unsigned long, caller[1], stack1) | ||
79 | TRACE_FIELD(unsigned long, caller[2], stack2) | ||
80 | TRACE_FIELD(unsigned long, caller[3], stack3) | ||
81 | TRACE_FIELD(unsigned long, caller[4], stack4) | ||
82 | TRACE_FIELD(unsigned long, caller[5], stack5) | ||
83 | TRACE_FIELD(unsigned long, caller[6], stack6) | ||
84 | TRACE_FIELD(unsigned long, caller[7], stack7) | ||
85 | ), | ||
86 | TPRAWFMT("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n" | ||
87 | "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n") | ||
88 | ); | ||
89 | |||
90 | TRACE_EVENT_FORMAT(user_stack, TRACE_USER_STACK, userstack_entry, ignore, | ||
91 | TRACE_STRUCT( | ||
92 | TRACE_FIELD(unsigned long, caller[0], stack0) | ||
93 | TRACE_FIELD(unsigned long, caller[1], stack1) | ||
94 | TRACE_FIELD(unsigned long, caller[2], stack2) | ||
95 | TRACE_FIELD(unsigned long, caller[3], stack3) | ||
96 | TRACE_FIELD(unsigned long, caller[4], stack4) | ||
97 | TRACE_FIELD(unsigned long, caller[5], stack5) | ||
98 | TRACE_FIELD(unsigned long, caller[6], stack6) | ||
99 | TRACE_FIELD(unsigned long, caller[7], stack7) | ||
100 | ), | ||
101 | TPRAWFMT("\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n" | ||
102 | "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n") | ||
103 | ); | ||
104 | |||
105 | TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore, | ||
106 | TRACE_STRUCT( | ||
107 | TRACE_FIELD(unsigned long, ip, ip) | ||
108 | TRACE_FIELD(unsigned int, depth, depth) | ||
109 | TRACE_FIELD_ZERO_CHAR(buf) | ||
110 | ), | ||
111 | TPRAWFMT("%08lx (%d) %s") | ||
112 | ); | ||
113 | |||
114 | TRACE_EVENT_FORMAT(branch, TRACE_BRANCH, trace_branch, ignore, | ||
115 | TRACE_STRUCT( | ||
116 | TRACE_FIELD(unsigned int, line, line) | ||
117 | TRACE_FIELD_SPECIAL(char func[TRACE_FUNC_SIZE+1], func, func) | ||
118 | TRACE_FIELD_SPECIAL(char file[TRACE_FUNC_SIZE+1], file, file) | ||
119 | TRACE_FIELD(char, correct, correct) | ||
120 | ), | ||
121 | TPRAWFMT("%u:%s:%s (%u)") | ||
122 | ); | ||
123 | |||
124 | TRACE_EVENT_FORMAT(hw_branch, TRACE_HW_BRANCHES, hw_branch_entry, ignore, | ||
125 | TRACE_STRUCT( | ||
126 | TRACE_FIELD(u64, from, from) | ||
127 | TRACE_FIELD(u64, to, to) | ||
128 | ), | ||
129 | TPRAWFMT("from: %llx to: %llx") | ||
130 | ); | ||
131 | |||
132 | TRACE_EVENT_FORMAT(power, TRACE_POWER, trace_power, ignore, | ||
133 | TRACE_STRUCT( | ||
134 | TRACE_FIELD(ktime_t, state_data.stamp, stamp) | ||
135 | TRACE_FIELD(ktime_t, state_data.end, end) | ||
136 | TRACE_FIELD(int, state_data.type, type) | ||
137 | TRACE_FIELD(int, state_data.state, state) | ||
138 | ), | ||
139 | TPRAWFMT("%llx->%llx type:%u state:%u") | ||
140 | ); | ||
141 | |||
142 | TRACE_EVENT_FORMAT(kmem_alloc, TRACE_KMEM_ALLOC, kmemtrace_alloc_entry, ignore, | ||
143 | TRACE_STRUCT( | ||
144 | TRACE_FIELD(enum kmemtrace_type_id, type_id, type_id) | ||
145 | TRACE_FIELD(unsigned long, call_site, call_site) | ||
146 | TRACE_FIELD(const void *, ptr, ptr) | ||
147 | TRACE_FIELD(size_t, bytes_req, bytes_req) | ||
148 | TRACE_FIELD(size_t, bytes_alloc, bytes_alloc) | ||
149 | TRACE_FIELD(gfp_t, gfp_flags, gfp_flags) | ||
150 | TRACE_FIELD(int, node, node) | ||
151 | ), | ||
152 | TPRAWFMT("type:%u call_site:%lx ptr:%p req:%lu alloc:%lu" | ||
153 | " flags:%x node:%d") | ||
154 | ); | ||
155 | |||
156 | TRACE_EVENT_FORMAT(kmem_free, TRACE_KMEM_FREE, kmemtrace_free_entry, ignore, | ||
157 | TRACE_STRUCT( | ||
158 | TRACE_FIELD(enum kmemtrace_type_id, type_id, type_id) | ||
159 | TRACE_FIELD(unsigned long, call_site, call_site) | ||
160 | TRACE_FIELD(const void *, ptr, ptr) | ||
161 | ), | ||
162 | TPRAWFMT("type:%u call_site:%lx ptr:%p") | ||
163 | ); | ||
164 | |||
165 | #undef TRACE_SYSTEM | ||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 210e71ff82db..4488d90e75ef 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -656,11 +656,13 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
656 | return -1; | 656 | return -1; |
657 | } | 657 | } |
658 | 658 | ||
659 | entry = debugfs_create_file("enable", 0644, call->dir, call, | 659 | if (call->regfunc) { |
660 | &ftrace_enable_fops); | 660 | entry = debugfs_create_file("enable", 0644, call->dir, call, |
661 | if (!entry) | 661 | &ftrace_enable_fops); |
662 | pr_warning("Could not create debugfs " | 662 | if (!entry) |
663 | "'%s/enable' entry\n", call->name); | 663 | pr_warning("Could not create debugfs " |
664 | "'%s/enable' entry\n", call->name); | ||
665 | } | ||
664 | 666 | ||
665 | /* Only let type be writable, if we can change it */ | 667 | /* Only let type be writable, if we can change it */ |
666 | entry = debugfs_create_file("type", | 668 | entry = debugfs_create_file("type", |
diff --git a/kernel/trace/trace_events_stage_2.h b/kernel/trace/trace_events_stage_2.h index b1cebba1d9b4..d24a97e74aea 100644 --- a/kernel/trace/trace_events_stage_2.h +++ b/kernel/trace/trace_events_stage_2.h | |||
@@ -75,56 +75,5 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ | |||
75 | 75 | ||
76 | #include <trace/trace_event_types.h> | 76 | #include <trace/trace_event_types.h> |
77 | 77 | ||
78 | /* | 78 | #include "trace_format.h" |
79 | * Setup the showing format of trace point. | ||
80 | * | ||
81 | * int | ||
82 | * ftrace_format_##call(struct trace_seq *s) | ||
83 | * { | ||
84 | * struct ftrace_raw_##call field; | ||
85 | * int ret; | ||
86 | * | ||
87 | * ret = trace_seq_printf(s, #type " " #item ";" | ||
88 | * " size:%d; offset:%d;\n", | ||
89 | * sizeof(field.type), | ||
90 | * offsetof(struct ftrace_raw_##call, | ||
91 | * item)); | ||
92 | * | ||
93 | * } | ||
94 | */ | ||
95 | |||
96 | #undef TRACE_FIELD | ||
97 | #define TRACE_FIELD(type, item, assign) \ | ||
98 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
99 | "offset:%lu;\tsize:%lu;\n", \ | ||
100 | offsetof(typeof(field), item), \ | ||
101 | sizeof(field.item)); \ | ||
102 | if (!ret) \ | ||
103 | return 0; | ||
104 | |||
105 | |||
106 | #undef TRACE_FIELD_SPECIAL | ||
107 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
108 | ret = trace_seq_printf(s, "\tfield special:" #type_item ";\t" \ | ||
109 | "offset:%lu;\tsize:%lu;\n", \ | ||
110 | offsetof(typeof(field), item), \ | ||
111 | sizeof(field.item)); \ | ||
112 | if (!ret) \ | ||
113 | return 0; | ||
114 | |||
115 | #undef TRACE_EVENT_FORMAT | ||
116 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
117 | int \ | ||
118 | ftrace_format_##call(struct trace_seq *s) \ | ||
119 | { \ | ||
120 | struct ftrace_raw_##call field; \ | ||
121 | int ret; \ | ||
122 | \ | ||
123 | tstruct; \ | ||
124 | \ | ||
125 | trace_seq_printf(s, "\nprint fmt: \"%s\"\n", tpfmt); \ | ||
126 | \ | ||
127 | return ret; \ | ||
128 | } | ||
129 | |||
130 | #include <trace/trace_event_types.h> | 79 | #include <trace/trace_event_types.h> |
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c new file mode 100644 index 000000000000..0fb7be73e31c --- /dev/null +++ b/kernel/trace/trace_export.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * trace_export.c - export basic ftrace utilities to user space | ||
3 | * | ||
4 | * Copyright (C) 2009 Steven Rostedt <srostedt@redhat.com> | ||
5 | */ | ||
6 | #include <linux/stringify.h> | ||
7 | #include <linux/kallsyms.h> | ||
8 | #include <linux/seq_file.h> | ||
9 | #include <linux/debugfs.h> | ||
10 | #include <linux/uaccess.h> | ||
11 | #include <linux/ftrace.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/fs.h> | ||
15 | |||
16 | #include "trace_output.h" | ||
17 | |||
18 | #include "trace_format.h" | ||
19 | |||
20 | #undef TRACE_FIELD_ZERO_CHAR | ||
21 | #define TRACE_FIELD_ZERO_CHAR(item) \ | ||
22 | ret = trace_seq_printf(s, "\tfield: char " #item ";\t" \ | ||
23 | "offset:%lu;\tsize:0;\n", \ | ||
24 | offsetof(typeof(field), item)); \ | ||
25 | if (!ret) \ | ||
26 | return 0; | ||
27 | |||
28 | |||
29 | #undef TPRAWFMT | ||
30 | #define TPRAWFMT(args...) args | ||
31 | |||
32 | #undef TRACE_EVENT_FORMAT | ||
33 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
34 | static int \ | ||
35 | ftrace_format_##call(struct trace_seq *s) \ | ||
36 | { \ | ||
37 | struct args field; \ | ||
38 | int ret; \ | ||
39 | \ | ||
40 | tstruct; \ | ||
41 | \ | ||
42 | trace_seq_printf(s, "\nprint fmt: \"%s\"\n", tpfmt); \ | ||
43 | \ | ||
44 | return ret; \ | ||
45 | } | ||
46 | |||
47 | #include "trace_event_types.h" | ||
48 | |||
49 | #undef TRACE_ZERO_CHAR | ||
50 | #define TRACE_ZERO_CHAR(arg) | ||
51 | |||
52 | #undef TRACE_FIELD | ||
53 | #define TRACE_FIELD(type, item, assign)\ | ||
54 | entry->item = assign; | ||
55 | |||
56 | #undef TRACE_FIELD | ||
57 | #define TRACE_FIELD(type, item, assign)\ | ||
58 | entry->item = assign; | ||
59 | |||
60 | #undef TPCMD | ||
61 | #define TPCMD(cmd...) cmd | ||
62 | |||
63 | #undef TRACE_ENTRY | ||
64 | #define TRACE_ENTRY entry | ||
65 | |||
66 | #undef TRACE_FIELD_SPECIAL | ||
67 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
68 | cmd; | ||
69 | |||
70 | #undef TRACE_EVENT_FORMAT | ||
71 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
72 | \ | ||
73 | static struct ftrace_event_call __used \ | ||
74 | __attribute__((__aligned__(4))) \ | ||
75 | __attribute__((section("_ftrace_events"))) event_##call = { \ | ||
76 | .name = #call, \ | ||
77 | .id = proto, \ | ||
78 | .system = __stringify(TRACE_SYSTEM), \ | ||
79 | .show_format = ftrace_format_##call, \ | ||
80 | } | ||
81 | #include "trace_event_types.h" | ||
diff --git a/kernel/trace/trace_format.h b/kernel/trace/trace_format.h new file mode 100644 index 000000000000..03f9a4c165ca --- /dev/null +++ b/kernel/trace/trace_format.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Setup the showing format of trace point. | ||
3 | * | ||
4 | * int | ||
5 | * ftrace_format_##call(struct trace_seq *s) | ||
6 | * { | ||
7 | * struct ftrace_raw_##call field; | ||
8 | * int ret; | ||
9 | * | ||
10 | * ret = trace_seq_printf(s, #type " " #item ";" | ||
11 | * " size:%d; offset:%d;\n", | ||
12 | * sizeof(field.type), | ||
13 | * offsetof(struct ftrace_raw_##call, | ||
14 | * item)); | ||
15 | * | ||
16 | * } | ||
17 | */ | ||
18 | |||
19 | #undef TRACE_STRUCT | ||
20 | #define TRACE_STRUCT(args...) args | ||
21 | |||
22 | #undef TRACE_FIELD | ||
23 | #define TRACE_FIELD(type, item, assign) \ | ||
24 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
25 | "offset:%lu;\tsize:%lu;\n", \ | ||
26 | offsetof(typeof(field), item), \ | ||
27 | sizeof(field.item)); \ | ||
28 | if (!ret) \ | ||
29 | return 0; | ||
30 | |||
31 | |||
32 | #undef TRACE_FIELD_SPECIAL | ||
33 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
34 | ret = trace_seq_printf(s, "\tfield special:" #type_item ";\t" \ | ||
35 | "offset:%lu;\tsize:%lu;\n", \ | ||
36 | offsetof(typeof(field), item), \ | ||
37 | sizeof(field.item)); \ | ||
38 | if (!ret) \ | ||
39 | return 0; | ||
40 | |||
41 | #undef TRACE_EVENT_FORMAT | ||
42 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
43 | static int \ | ||
44 | ftrace_format_##call(struct trace_seq *s) \ | ||
45 | { \ | ||
46 | struct ftrace_raw_##call field; \ | ||
47 | int ret; \ | ||
48 | \ | ||
49 | tstruct; \ | ||
50 | \ | ||
51 | trace_seq_printf(s, "\nprint fmt: \"%s\"\n", tpfmt); \ | ||
52 | \ | ||
53 | return ret; \ | ||
54 | } | ||
55 | |||
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index e527f2f66c73..453ebd3b636e 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -742,7 +742,11 @@ print_graph_comment(struct print_entry *trace, struct trace_seq *s, | |||
742 | } | 742 | } |
743 | 743 | ||
744 | /* The comment */ | 744 | /* The comment */ |
745 | ret = trace_seq_printf(s, "/* %s", trace->buf); | 745 | ret = trace_seq_printf(s, "/* "); |
746 | if (!ret) | ||
747 | return TRACE_TYPE_PARTIAL_LINE; | ||
748 | |||
749 | ret = trace_seq_bprintf(s, trace->fmt, trace->buf); | ||
746 | if (!ret) | 750 | if (!ret) |
747 | return TRACE_TYPE_PARTIAL_LINE; | 751 | return TRACE_TYPE_PARTIAL_LINE; |
748 | 752 | ||
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c index c401b908e805..23e346a734ca 100644 --- a/kernel/trace/trace_mmiotrace.c +++ b/kernel/trace/trace_mmiotrace.c | |||
@@ -254,15 +254,18 @@ static enum print_line_t mmio_print_mark(struct trace_iterator *iter) | |||
254 | { | 254 | { |
255 | struct trace_entry *entry = iter->ent; | 255 | struct trace_entry *entry = iter->ent; |
256 | struct print_entry *print = (struct print_entry *)entry; | 256 | struct print_entry *print = (struct print_entry *)entry; |
257 | const char *msg = print->buf; | ||
258 | struct trace_seq *s = &iter->seq; | 257 | struct trace_seq *s = &iter->seq; |
259 | unsigned long long t = ns2usecs(iter->ts); | 258 | unsigned long long t = ns2usecs(iter->ts); |
260 | unsigned long usec_rem = do_div(t, 1000000ULL); | 259 | unsigned long usec_rem = do_div(t, USEC_PER_SEC); |
261 | unsigned secs = (unsigned long)t; | 260 | unsigned secs = (unsigned long)t; |
262 | int ret; | 261 | int ret; |
263 | 262 | ||
264 | /* The trailing newline must be in the message. */ | 263 | /* The trailing newline must be in the message. */ |
265 | ret = trace_seq_printf(s, "MARK %u.%06lu %s", secs, usec_rem, msg); | 264 | ret = trace_seq_printf(s, "MARK %u.%06lu ", secs, usec_rem); |
265 | if (!ret) | ||
266 | return TRACE_TYPE_PARTIAL_LINE; | ||
267 | |||
268 | ret = trace_seq_bprintf(s, print->fmt, print->buf); | ||
266 | if (!ret) | 269 | if (!ret) |
267 | return TRACE_TYPE_PARTIAL_LINE; | 270 | return TRACE_TYPE_PARTIAL_LINE; |
268 | 271 | ||
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 306fef84c503..ef8fd661b217 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
@@ -53,6 +53,25 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | |||
53 | return len; | 53 | return len; |
54 | } | 54 | } |
55 | 55 | ||
56 | int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) | ||
57 | { | ||
58 | int len = (PAGE_SIZE - 1) - s->len; | ||
59 | int ret; | ||
60 | |||
61 | if (!len) | ||
62 | return 0; | ||
63 | |||
64 | ret = bstr_printf(s->buffer + s->len, len, fmt, binary); | ||
65 | |||
66 | /* If we can't write it all, don't bother writing anything */ | ||
67 | if (ret >= len) | ||
68 | return 0; | ||
69 | |||
70 | s->len += ret; | ||
71 | |||
72 | return len; | ||
73 | } | ||
74 | |||
56 | /** | 75 | /** |
57 | * trace_seq_puts - trace sequence printing of simple string | 76 | * trace_seq_puts - trace sequence printing of simple string |
58 | * @s: trace sequence descriptor | 77 | * @s: trace sequence descriptor |
@@ -814,18 +833,22 @@ static struct trace_event trace_user_stack_event = { | |||
814 | }; | 833 | }; |
815 | 834 | ||
816 | /* TRACE_PRINT */ | 835 | /* TRACE_PRINT */ |
817 | static enum print_line_t trace_print_print(struct trace_iterator *iter, | 836 | static enum print_line_t |
818 | int flags) | 837 | trace_print_print(struct trace_iterator *iter, int flags) |
819 | { | 838 | { |
820 | struct print_entry *field; | 839 | struct trace_entry *entry = iter->ent; |
821 | struct trace_seq *s = &iter->seq; | 840 | struct trace_seq *s = &iter->seq; |
841 | struct print_entry *field; | ||
822 | 842 | ||
823 | trace_assign_type(field, iter->ent); | 843 | trace_assign_type(field, entry); |
824 | 844 | ||
825 | if (!seq_print_ip_sym(s, field->ip, flags)) | 845 | if (!seq_print_ip_sym(s, field->ip, flags)) |
826 | goto partial; | 846 | goto partial; |
827 | 847 | ||
828 | if (!trace_seq_printf(s, ": %s", field->buf)) | 848 | if (!trace_seq_puts(s, ": ")) |
849 | goto partial; | ||
850 | |||
851 | if (!trace_seq_bprintf(s, field->fmt, field->buf)) | ||
829 | goto partial; | 852 | goto partial; |
830 | 853 | ||
831 | return TRACE_TYPE_HANDLED; | 854 | return TRACE_TYPE_HANDLED; |
@@ -834,13 +857,18 @@ static enum print_line_t trace_print_print(struct trace_iterator *iter, | |||
834 | return TRACE_TYPE_PARTIAL_LINE; | 857 | return TRACE_TYPE_PARTIAL_LINE; |
835 | } | 858 | } |
836 | 859 | ||
860 | |||
837 | static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags) | 861 | static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags) |
838 | { | 862 | { |
839 | struct print_entry *field; | 863 | struct print_entry *field; |
864 | struct trace_seq *s = &iter->seq; | ||
840 | 865 | ||
841 | trace_assign_type(field, iter->ent); | 866 | trace_assign_type(field, iter->ent); |
842 | 867 | ||
843 | if (!trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf)) | 868 | if (!trace_seq_printf(s, ": %lx : ", field->ip)) |
869 | goto partial; | ||
870 | |||
871 | if (!trace_seq_bprintf(s, field->fmt, field->buf)) | ||
844 | goto partial; | 872 | goto partial; |
845 | 873 | ||
846 | return TRACE_TYPE_HANDLED; | 874 | return TRACE_TYPE_HANDLED; |
@@ -849,6 +877,7 @@ static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags) | |||
849 | return TRACE_TYPE_PARTIAL_LINE; | 877 | return TRACE_TYPE_PARTIAL_LINE; |
850 | } | 878 | } |
851 | 879 | ||
880 | |||
852 | static struct trace_event trace_print_event = { | 881 | static struct trace_event trace_print_event = { |
853 | .type = TRACE_PRINT, | 882 | .type = TRACE_PRINT, |
854 | .trace = trace_print_print, | 883 | .trace = trace_print_print, |
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h index 8a34d688ed63..3b90e6ade1aa 100644 --- a/kernel/trace/trace_output.h +++ b/kernel/trace/trace_output.h | |||
@@ -18,6 +18,8 @@ struct trace_event { | |||
18 | extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | 18 | extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) |
19 | __attribute__ ((format (printf, 2, 3))); | 19 | __attribute__ ((format (printf, 2, 3))); |
20 | extern int | 20 | extern int |
21 | trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); | ||
22 | extern int | ||
21 | seq_print_ip_sym(struct trace_seq *s, unsigned long ip, | 23 | seq_print_ip_sym(struct trace_seq *s, unsigned long ip, |
22 | unsigned long sym_flags); | 24 | unsigned long sym_flags); |
23 | extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, | 25 | extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, |
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c new file mode 100644 index 000000000000..a50aea22e929 --- /dev/null +++ b/kernel/trace/trace_printk.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * trace binary printk | ||
3 | * | ||
4 | * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com> | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/ftrace.h> | ||
9 | #include <linux/string.h> | ||
10 | #include <linux/ctype.h> | ||
11 | #include <linux/list.h> | ||
12 | #include <linux/mutex.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/marker.h> | ||
18 | #include <linux/uaccess.h> | ||
19 | |||
20 | #include "trace.h" | ||
21 | |||
22 | #ifdef CONFIG_MODULES | ||
23 | |||
24 | /* | ||
25 | * modules trace_printk()'s formats are autosaved in struct trace_bprintk_fmt | ||
26 | * which are queued on trace_bprintk_fmt_list. | ||
27 | */ | ||
28 | static LIST_HEAD(trace_bprintk_fmt_list); | ||
29 | |||
30 | /* serialize accesses to trace_bprintk_fmt_list */ | ||
31 | static DEFINE_MUTEX(btrace_mutex); | ||
32 | |||
33 | struct trace_bprintk_fmt { | ||
34 | struct list_head list; | ||
35 | char fmt[0]; | ||
36 | }; | ||
37 | |||
38 | static inline struct trace_bprintk_fmt *lookup_format(const char *fmt) | ||
39 | { | ||
40 | struct trace_bprintk_fmt *pos; | ||
41 | list_for_each_entry(pos, &trace_bprintk_fmt_list, list) { | ||
42 | if (!strcmp(pos->fmt, fmt)) | ||
43 | return pos; | ||
44 | } | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
48 | static | ||
49 | void hold_module_trace_bprintk_format(const char **start, const char **end) | ||
50 | { | ||
51 | const char **iter; | ||
52 | |||
53 | mutex_lock(&btrace_mutex); | ||
54 | for (iter = start; iter < end; iter++) { | ||
55 | struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter); | ||
56 | if (tb_fmt) { | ||
57 | *iter = tb_fmt->fmt; | ||
58 | continue; | ||
59 | } | ||
60 | |||
61 | tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt) | ||
62 | + strlen(*iter) + 1, GFP_KERNEL); | ||
63 | if (tb_fmt) { | ||
64 | list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list); | ||
65 | strcpy(tb_fmt->fmt, *iter); | ||
66 | *iter = tb_fmt->fmt; | ||
67 | } else | ||
68 | *iter = NULL; | ||
69 | } | ||
70 | mutex_unlock(&btrace_mutex); | ||
71 | } | ||
72 | |||
73 | static int module_trace_bprintk_format_notify(struct notifier_block *self, | ||
74 | unsigned long val, void *data) | ||
75 | { | ||
76 | struct module *mod = data; | ||
77 | if (mod->num_trace_bprintk_fmt) { | ||
78 | const char **start = mod->trace_bprintk_fmt_start; | ||
79 | const char **end = start + mod->num_trace_bprintk_fmt; | ||
80 | |||
81 | if (val == MODULE_STATE_COMING) | ||
82 | hold_module_trace_bprintk_format(start, end); | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | #else /* !CONFIG_MODULES */ | ||
88 | __init static int | ||
89 | module_trace_bprintk_format_notify(struct notifier_block *self, | ||
90 | unsigned long val, void *data) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | #endif /* CONFIG_MODULES */ | ||
95 | |||
96 | |||
97 | __initdata_or_module static | ||
98 | struct notifier_block module_trace_bprintk_format_nb = { | ||
99 | .notifier_call = module_trace_bprintk_format_notify, | ||
100 | }; | ||
101 | |||
102 | int __trace_printk(unsigned long ip, const char *fmt, ...) | ||
103 | { | ||
104 | int ret; | ||
105 | va_list ap; | ||
106 | |||
107 | if (unlikely(!fmt)) | ||
108 | return 0; | ||
109 | |||
110 | if (!(trace_flags & TRACE_ITER_PRINTK)) | ||
111 | return 0; | ||
112 | |||
113 | va_start(ap, fmt); | ||
114 | ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); | ||
115 | va_end(ap); | ||
116 | return ret; | ||
117 | } | ||
118 | EXPORT_SYMBOL_GPL(__trace_printk); | ||
119 | |||
120 | int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) | ||
121 | { | ||
122 | if (unlikely(!fmt)) | ||
123 | return 0; | ||
124 | |||
125 | if (!(trace_flags & TRACE_ITER_PRINTK)) | ||
126 | return 0; | ||
127 | |||
128 | return trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(__ftrace_vprintk); | ||
131 | |||
132 | |||
133 | static __init int init_trace_printk(void) | ||
134 | { | ||
135 | return register_module_notifier(&module_trace_bprintk_format_nb); | ||
136 | } | ||
137 | |||
138 | early_initcall(init_trace_printk); | ||
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index c771af4e8f1a..91fd19c2149f 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c | |||
@@ -314,7 +314,7 @@ sysprof_sample_write(struct file *filp, const char __user *ubuf, | |||
314 | return cnt; | 314 | return cnt; |
315 | } | 315 | } |
316 | 316 | ||
317 | static struct file_operations sysprof_sample_fops = { | 317 | static const struct file_operations sysprof_sample_fops = { |
318 | .read = sysprof_sample_read, | 318 | .read = sysprof_sample_read, |
319 | .write = sysprof_sample_write, | 319 | .write = sysprof_sample_write, |
320 | }; | 320 | }; |