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 | }; | 
