diff options
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 9 | ||||
-rw-r--r-- | include/linux/ftrace.h | 1 | ||||
-rw-r--r-- | include/linux/kernel.h | 80 | ||||
-rw-r--r-- | include/linux/module.h | 5 | ||||
-rw-r--r-- | include/linux/ring_buffer.h | 15 | ||||
-rw-r--r-- | include/linux/string.h | 7 | ||||
-rw-r--r-- | include/trace/power.h | 2 | ||||
-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 | ||||
-rw-r--r-- | lib/Kconfig | 3 | ||||
-rw-r--r-- | lib/vsprintf.c | 1006 |
26 files changed, 1468 insertions, 427 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 9d974914e914..89997dfdf3d0 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -69,6 +69,14 @@ | |||
69 | #define FTRACE_EVENTS() | 69 | #define FTRACE_EVENTS() |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #ifdef CONFIG_TRACING | ||
73 | #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \ | ||
74 | *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \ | ||
75 | VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .; | ||
76 | #else | ||
77 | #define TRACE_PRINTKS() | ||
78 | #endif | ||
79 | |||
72 | /* .data section */ | 80 | /* .data section */ |
73 | #define DATA_DATA \ | 81 | #define DATA_DATA \ |
74 | *(.data) \ | 82 | *(.data) \ |
@@ -100,6 +108,7 @@ | |||
100 | *(__vermagic) /* Kernel version magic */ \ | 108 | *(__vermagic) /* Kernel version magic */ \ |
101 | *(__markers_strings) /* Markers: strings */ \ | 109 | *(__markers_strings) /* Markers: strings */ \ |
102 | *(__tracepoints_strings)/* Tracepoints: strings */ \ | 110 | *(__tracepoints_strings)/* Tracepoints: strings */ \ |
111 | TRACE_PRINTKS() \ | ||
103 | } \ | 112 | } \ |
104 | \ | 113 | \ |
105 | .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ | 114 | .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ |
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 498769425eb2..e1583f2639b0 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -223,7 +223,6 @@ extern int ftrace_make_nop(struct module *mod, | |||
223 | */ | 223 | */ |
224 | extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr); | 224 | extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr); |
225 | 225 | ||
226 | |||
227 | /* May be defined in arch */ | 226 | /* May be defined in arch */ |
228 | extern int ftrace_arch_read_dyn_info(char *buf, int size); | 227 | extern int ftrace_arch_read_dyn_info(char *buf, int size); |
229 | 228 | ||
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 08bf5da86676..4e726b9a71ec 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -242,6 +242,19 @@ extern struct ratelimit_state printk_ratelimit_state; | |||
242 | extern int printk_ratelimit(void); | 242 | extern int printk_ratelimit(void); |
243 | extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, | 243 | extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, |
244 | unsigned int interval_msec); | 244 | unsigned int interval_msec); |
245 | |||
246 | /* | ||
247 | * Print a one-time message (analogous to WARN_ONCE() et al): | ||
248 | */ | ||
249 | #define printk_once(x...) ({ \ | ||
250 | static int __print_once = 1; \ | ||
251 | \ | ||
252 | if (__print_once) { \ | ||
253 | __print_once = 0; \ | ||
254 | printk(x); \ | ||
255 | } \ | ||
256 | }) | ||
257 | |||
245 | #else | 258 | #else |
246 | static inline int vprintk(const char *s, va_list args) | 259 | static inline int vprintk(const char *s, va_list args) |
247 | __attribute__ ((format (printf, 1, 0))); | 260 | __attribute__ ((format (printf, 1, 0))); |
@@ -253,6 +266,10 @@ static inline int printk_ratelimit(void) { return 0; } | |||
253 | static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \ | 266 | static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \ |
254 | unsigned int interval_msec) \ | 267 | unsigned int interval_msec) \ |
255 | { return false; } | 268 | { return false; } |
269 | |||
270 | /* No effect, but we still get type checking even in the !PRINTK case: */ | ||
271 | #define printk_once(x...) printk(x) | ||
272 | |||
256 | #endif | 273 | #endif |
257 | 274 | ||
258 | extern int printk_needs_cpu(int cpu); | 275 | extern int printk_needs_cpu(int cpu); |
@@ -369,8 +386,35 @@ static inline char *pack_hex_byte(char *buf, u8 byte) | |||
369 | 386 | ||
370 | /* | 387 | /* |
371 | * General tracing related utility functions - trace_printk(), | 388 | * General tracing related utility functions - trace_printk(), |
372 | * tracing_start()/tracing_stop: | 389 | * tracing_on/tracing_off and tracing_start()/tracing_stop |
390 | * | ||
391 | * Use tracing_on/tracing_off when you want to quickly turn on or off | ||
392 | * tracing. It simply enables or disables the recording of the trace events. | ||
393 | * This also corresponds to the user space debugfs/tracing/tracing_on | ||
394 | * file, which gives a means for the kernel and userspace to interact. | ||
395 | * Place a tracing_off() in the kernel where you want tracing to end. | ||
396 | * From user space, examine the trace, and then echo 1 > tracing_on | ||
397 | * to continue tracing. | ||
398 | * | ||
399 | * tracing_stop/tracing_start has slightly more overhead. It is used | ||
400 | * by things like suspend to ram where disabling the recording of the | ||
401 | * trace is not enough, but tracing must actually stop because things | ||
402 | * like calling smp_processor_id() may crash the system. | ||
403 | * | ||
404 | * Most likely, you want to use tracing_on/tracing_off. | ||
373 | */ | 405 | */ |
406 | #ifdef CONFIG_RING_BUFFER | ||
407 | void tracing_on(void); | ||
408 | void tracing_off(void); | ||
409 | /* trace_off_permanent stops recording with no way to bring it back */ | ||
410 | void tracing_off_permanent(void); | ||
411 | int tracing_is_on(void); | ||
412 | #else | ||
413 | static inline void tracing_on(void) { } | ||
414 | static inline void tracing_off(void) { } | ||
415 | static inline void tracing_off_permanent(void) { } | ||
416 | static inline int tracing_is_on(void) { return 0; } | ||
417 | #endif | ||
374 | #ifdef CONFIG_TRACING | 418 | #ifdef CONFIG_TRACING |
375 | extern void tracing_start(void); | 419 | extern void tracing_start(void); |
376 | extern void tracing_stop(void); | 420 | extern void tracing_stop(void); |
@@ -379,6 +423,16 @@ extern void ftrace_off_permanent(void); | |||
379 | extern void | 423 | extern void |
380 | ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3); | 424 | ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3); |
381 | 425 | ||
426 | static inline void __attribute__ ((format (printf, 1, 2))) | ||
427 | ____trace_printk_check_format(const char *fmt, ...) | ||
428 | { | ||
429 | } | ||
430 | #define __trace_printk_check_format(fmt, args...) \ | ||
431 | do { \ | ||
432 | if (0) \ | ||
433 | ____trace_printk_check_format(fmt, ##args); \ | ||
434 | } while (0) | ||
435 | |||
382 | /** | 436 | /** |
383 | * trace_printk - printf formatting in the ftrace buffer | 437 | * trace_printk - printf formatting in the ftrace buffer |
384 | * @fmt: the printf format for printing | 438 | * @fmt: the printf format for printing |
@@ -395,13 +449,31 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3); | |||
395 | * Please refrain from leaving trace_printks scattered around in | 449 | * Please refrain from leaving trace_printks scattered around in |
396 | * your code. | 450 | * your code. |
397 | */ | 451 | */ |
398 | # define trace_printk(fmt...) __trace_printk(_THIS_IP_, fmt) | 452 | |
453 | #define trace_printk(fmt, args...) \ | ||
454 | do { \ | ||
455 | static const char *trace_printk_fmt \ | ||
456 | __attribute__((section("__trace_printk_fmt"))); \ | ||
457 | trace_printk_fmt = fmt; \ | ||
458 | __trace_printk_check_format(fmt, ##args); \ | ||
459 | __trace_printk(_THIS_IP_, trace_printk_fmt, ##args); \ | ||
460 | } while (0) | ||
461 | |||
399 | extern int | 462 | extern int |
400 | __trace_printk(unsigned long ip, const char *fmt, ...) | 463 | __trace_printk(unsigned long ip, const char *fmt, ...) |
401 | __attribute__ ((format (printf, 2, 3))); | 464 | __attribute__ ((format (printf, 2, 3))); |
402 | # define ftrace_vprintk(fmt, ap) __trace_printk(_THIS_IP_, fmt, ap) | 465 | |
466 | #define ftrace_vprintk(fmt, vargs) \ | ||
467 | do { \ | ||
468 | static const char *trace_printk_fmt \ | ||
469 | __attribute__((section("__trace_printk_fmt"))); \ | ||
470 | trace_printk_fmt = fmt; \ | ||
471 | __ftrace_vprintk(_THIS_IP_, trace_printk_fmt, vargs); \ | ||
472 | } while (0) | ||
473 | |||
403 | extern int | 474 | extern int |
404 | __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap); | 475 | __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap); |
476 | |||
405 | extern void ftrace_dump(void); | 477 | extern void ftrace_dump(void); |
406 | #else | 478 | #else |
407 | static inline void | 479 | static inline void |
@@ -423,7 +495,7 @@ ftrace_vprintk(const char *fmt, va_list ap) | |||
423 | return 0; | 495 | return 0; |
424 | } | 496 | } |
425 | static inline void ftrace_dump(void) { } | 497 | static inline void ftrace_dump(void) { } |
426 | #endif | 498 | #endif /* CONFIG_TRACING */ |
427 | 499 | ||
428 | /* | 500 | /* |
429 | * Display an IP address in readable format. | 501 | * Display an IP address in readable format. |
diff --git a/include/linux/module.h b/include/linux/module.h index 145a75528cc1..22d9878e868c 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -329,6 +329,11 @@ struct module | |||
329 | unsigned int num_tracepoints; | 329 | unsigned int num_tracepoints; |
330 | #endif | 330 | #endif |
331 | 331 | ||
332 | #ifdef CONFIG_TRACING | ||
333 | const char **trace_bprintk_fmt_start; | ||
334 | unsigned int num_trace_bprintk_fmt; | ||
335 | #endif | ||
336 | |||
332 | #ifdef CONFIG_MODULE_UNLOAD | 337 | #ifdef CONFIG_MODULE_UNLOAD |
333 | /* What modules depend on me? */ | 338 | /* What modules depend on me? */ |
334 | struct list_head modules_which_use_me; | 339 | struct list_head modules_which_use_me; |
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 79fcbc4b09d6..b1a0068a5557 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h | |||
@@ -124,21 +124,6 @@ void ring_buffer_normalize_time_stamp(int cpu, u64 *ts); | |||
124 | size_t ring_buffer_page_len(void *page); | 124 | size_t ring_buffer_page_len(void *page); |
125 | 125 | ||
126 | 126 | ||
127 | /* | ||
128 | * The below functions are fine to use outside the tracing facility. | ||
129 | */ | ||
130 | #ifdef CONFIG_RING_BUFFER | ||
131 | void tracing_on(void); | ||
132 | void tracing_off(void); | ||
133 | void tracing_off_permanent(void); | ||
134 | int tracing_is_on(void); | ||
135 | #else | ||
136 | static inline void tracing_on(void) { } | ||
137 | static inline void tracing_off(void) { } | ||
138 | static inline void tracing_off_permanent(void) { } | ||
139 | static inline int tracing_is_on(void) { return 0; } | ||
140 | #endif | ||
141 | |||
142 | void *ring_buffer_alloc_read_page(struct ring_buffer *buffer); | 127 | void *ring_buffer_alloc_read_page(struct ring_buffer *buffer); |
143 | void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); | 128 | void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); |
144 | int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, | 129 | int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, |
diff --git a/include/linux/string.h b/include/linux/string.h index d18fc198aa2f..27ac31784ad2 100644 --- a/include/linux/string.h +++ b/include/linux/string.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/compiler.h> /* for inline */ | 10 | #include <linux/compiler.h> /* for inline */ |
11 | #include <linux/types.h> /* for size_t */ | 11 | #include <linux/types.h> /* for size_t */ |
12 | #include <linux/stddef.h> /* for NULL */ | 12 | #include <linux/stddef.h> /* for NULL */ |
13 | #include <stdarg.h> | ||
13 | 14 | ||
14 | extern char *strndup_user(const char __user *, long); | 15 | extern char *strndup_user(const char __user *, long); |
15 | 16 | ||
@@ -111,6 +112,12 @@ extern void argv_free(char **argv); | |||
111 | 112 | ||
112 | extern bool sysfs_streq(const char *s1, const char *s2); | 113 | extern bool sysfs_streq(const char *s1, const char *s2); |
113 | 114 | ||
115 | #ifdef CONFIG_BINARY_PRINTF | ||
116 | int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); | ||
117 | int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf); | ||
118 | int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); | ||
119 | #endif | ||
120 | |||
114 | extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, | 121 | extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, |
115 | const void *from, size_t available); | 122 | const void *from, size_t available); |
116 | 123 | ||
diff --git a/include/trace/power.h b/include/trace/power.h index 2c733e58e89c..38aca537e497 100644 --- a/include/trace/power.h +++ b/include/trace/power.h | |||
@@ -11,12 +11,10 @@ enum { | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | struct power_trace { | 13 | struct power_trace { |
14 | #ifdef CONFIG_POWER_TRACER | ||
15 | ktime_t stamp; | 14 | ktime_t stamp; |
16 | ktime_t end; | 15 | ktime_t end; |
17 | int type; | 16 | int type; |
18 | int state; | 17 | int state; |
19 | #endif | ||
20 | }; | 18 | }; |
21 | 19 | ||
22 | DECLARE_TRACE(power_start, | 20 | DECLARE_TRACE(power_start, |
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 | }; |
diff --git a/lib/Kconfig b/lib/Kconfig index daa481824d9c..206f36a9efb4 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -2,6 +2,9 @@ | |||
2 | # Library configuration | 2 | # Library configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | config BINARY_PRINTF | ||
6 | def_bool n | ||
7 | |||
5 | menu "Library routines" | 8 | menu "Library routines" |
6 | 9 | ||
7 | config BITREVERSE | 10 | config BITREVERSE |
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0fbd0121d91d..25f01578c856 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -396,7 +396,38 @@ static noinline char* put_dec(char *buf, unsigned long long num) | |||
396 | #define SMALL 32 /* Must be 32 == 0x20 */ | 396 | #define SMALL 32 /* Must be 32 == 0x20 */ |
397 | #define SPECIAL 64 /* 0x */ | 397 | #define SPECIAL 64 /* 0x */ |
398 | 398 | ||
399 | static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) | 399 | enum format_type { |
400 | FORMAT_TYPE_NONE, /* Just a string part */ | ||
401 | FORMAT_TYPE_WITDH, | ||
402 | FORMAT_TYPE_PRECISION, | ||
403 | FORMAT_TYPE_CHAR, | ||
404 | FORMAT_TYPE_STR, | ||
405 | FORMAT_TYPE_PTR, | ||
406 | FORMAT_TYPE_PERCENT_CHAR, | ||
407 | FORMAT_TYPE_INVALID, | ||
408 | FORMAT_TYPE_LONG_LONG, | ||
409 | FORMAT_TYPE_ULONG, | ||
410 | FORMAT_TYPE_LONG, | ||
411 | FORMAT_TYPE_USHORT, | ||
412 | FORMAT_TYPE_SHORT, | ||
413 | FORMAT_TYPE_UINT, | ||
414 | FORMAT_TYPE_INT, | ||
415 | FORMAT_TYPE_NRCHARS, | ||
416 | FORMAT_TYPE_SIZE_T, | ||
417 | FORMAT_TYPE_PTRDIFF | ||
418 | }; | ||
419 | |||
420 | struct printf_spec { | ||
421 | enum format_type type; | ||
422 | int flags; /* flags to number() */ | ||
423 | int field_width; /* width of output field */ | ||
424 | int base; | ||
425 | int precision; /* # of digits/chars */ | ||
426 | int qualifier; | ||
427 | }; | ||
428 | |||
429 | static char *number(char *buf, char *end, unsigned long long num, | ||
430 | struct printf_spec spec) | ||
400 | { | 431 | { |
401 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ | 432 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
402 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ | 433 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
@@ -404,32 +435,32 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
404 | char tmp[66]; | 435 | char tmp[66]; |
405 | char sign; | 436 | char sign; |
406 | char locase; | 437 | char locase; |
407 | int need_pfx = ((type & SPECIAL) && base != 10); | 438 | int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); |
408 | int i; | 439 | int i; |
409 | 440 | ||
410 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' | 441 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' |
411 | * produces same digits or (maybe lowercased) letters */ | 442 | * produces same digits or (maybe lowercased) letters */ |
412 | locase = (type & SMALL); | 443 | locase = (spec.flags & SMALL); |
413 | if (type & LEFT) | 444 | if (spec.flags & LEFT) |
414 | type &= ~ZEROPAD; | 445 | spec.flags &= ~ZEROPAD; |
415 | sign = 0; | 446 | sign = 0; |
416 | if (type & SIGN) { | 447 | if (spec.flags & SIGN) { |
417 | if ((signed long long) num < 0) { | 448 | if ((signed long long) num < 0) { |
418 | sign = '-'; | 449 | sign = '-'; |
419 | num = - (signed long long) num; | 450 | num = - (signed long long) num; |
420 | size--; | 451 | spec.field_width--; |
421 | } else if (type & PLUS) { | 452 | } else if (spec.flags & PLUS) { |
422 | sign = '+'; | 453 | sign = '+'; |
423 | size--; | 454 | spec.field_width--; |
424 | } else if (type & SPACE) { | 455 | } else if (spec.flags & SPACE) { |
425 | sign = ' '; | 456 | sign = ' '; |
426 | size--; | 457 | spec.field_width--; |
427 | } | 458 | } |
428 | } | 459 | } |
429 | if (need_pfx) { | 460 | if (need_pfx) { |
430 | size--; | 461 | spec.field_width--; |
431 | if (base == 16) | 462 | if (spec.base == 16) |
432 | size--; | 463 | spec.field_width--; |
433 | } | 464 | } |
434 | 465 | ||
435 | /* generate full string in tmp[], in reverse order */ | 466 | /* generate full string in tmp[], in reverse order */ |
@@ -441,10 +472,10 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
441 | tmp[i++] = (digits[do_div(num,base)] | locase); | 472 | tmp[i++] = (digits[do_div(num,base)] | locase); |
442 | } while (num != 0); | 473 | } while (num != 0); |
443 | */ | 474 | */ |
444 | else if (base != 10) { /* 8 or 16 */ | 475 | else if (spec.base != 10) { /* 8 or 16 */ |
445 | int mask = base - 1; | 476 | int mask = spec.base - 1; |
446 | int shift = 3; | 477 | int shift = 3; |
447 | if (base == 16) shift = 4; | 478 | if (spec.base == 16) shift = 4; |
448 | do { | 479 | do { |
449 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); | 480 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
450 | num >>= shift; | 481 | num >>= shift; |
@@ -454,12 +485,12 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
454 | } | 485 | } |
455 | 486 | ||
456 | /* printing 100 using %2d gives "100", not "00" */ | 487 | /* printing 100 using %2d gives "100", not "00" */ |
457 | if (i > precision) | 488 | if (i > spec.precision) |
458 | precision = i; | 489 | spec.precision = i; |
459 | /* leading space padding */ | 490 | /* leading space padding */ |
460 | size -= precision; | 491 | spec.field_width -= spec.precision; |
461 | if (!(type & (ZEROPAD+LEFT))) { | 492 | if (!(spec.flags & (ZEROPAD+LEFT))) { |
462 | while(--size >= 0) { | 493 | while(--spec.field_width >= 0) { |
463 | if (buf < end) | 494 | if (buf < end) |
464 | *buf = ' '; | 495 | *buf = ' '; |
465 | ++buf; | 496 | ++buf; |
@@ -476,23 +507,23 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
476 | if (buf < end) | 507 | if (buf < end) |
477 | *buf = '0'; | 508 | *buf = '0'; |
478 | ++buf; | 509 | ++buf; |
479 | if (base == 16) { | 510 | if (spec.base == 16) { |
480 | if (buf < end) | 511 | if (buf < end) |
481 | *buf = ('X' | locase); | 512 | *buf = ('X' | locase); |
482 | ++buf; | 513 | ++buf; |
483 | } | 514 | } |
484 | } | 515 | } |
485 | /* zero or space padding */ | 516 | /* zero or space padding */ |
486 | if (!(type & LEFT)) { | 517 | if (!(spec.flags & LEFT)) { |
487 | char c = (type & ZEROPAD) ? '0' : ' '; | 518 | char c = (spec.flags & ZEROPAD) ? '0' : ' '; |
488 | while (--size >= 0) { | 519 | while (--spec.field_width >= 0) { |
489 | if (buf < end) | 520 | if (buf < end) |
490 | *buf = c; | 521 | *buf = c; |
491 | ++buf; | 522 | ++buf; |
492 | } | 523 | } |
493 | } | 524 | } |
494 | /* hmm even more zero padding? */ | 525 | /* hmm even more zero padding? */ |
495 | while (i <= --precision) { | 526 | while (i <= --spec.precision) { |
496 | if (buf < end) | 527 | if (buf < end) |
497 | *buf = '0'; | 528 | *buf = '0'; |
498 | ++buf; | 529 | ++buf; |
@@ -504,7 +535,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
504 | ++buf; | 535 | ++buf; |
505 | } | 536 | } |
506 | /* trailing space padding */ | 537 | /* trailing space padding */ |
507 | while (--size >= 0) { | 538 | while (--spec.field_width >= 0) { |
508 | if (buf < end) | 539 | if (buf < end) |
509 | *buf = ' '; | 540 | *buf = ' '; |
510 | ++buf; | 541 | ++buf; |
@@ -512,17 +543,17 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
512 | return buf; | 543 | return buf; |
513 | } | 544 | } |
514 | 545 | ||
515 | static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags) | 546 | static char *string(char *buf, char *end, char *s, struct printf_spec spec) |
516 | { | 547 | { |
517 | int len, i; | 548 | int len, i; |
518 | 549 | ||
519 | if ((unsigned long)s < PAGE_SIZE) | 550 | if ((unsigned long)s < PAGE_SIZE) |
520 | s = "<NULL>"; | 551 | s = "<NULL>"; |
521 | 552 | ||
522 | len = strnlen(s, precision); | 553 | len = strnlen(s, spec.precision); |
523 | 554 | ||
524 | if (!(flags & LEFT)) { | 555 | if (!(spec.flags & LEFT)) { |
525 | while (len < field_width--) { | 556 | while (len < spec.field_width--) { |
526 | if (buf < end) | 557 | if (buf < end) |
527 | *buf = ' '; | 558 | *buf = ' '; |
528 | ++buf; | 559 | ++buf; |
@@ -533,7 +564,7 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio | |||
533 | *buf = *s; | 564 | *buf = *s; |
534 | ++buf; ++s; | 565 | ++buf; ++s; |
535 | } | 566 | } |
536 | while (len < field_width--) { | 567 | while (len < spec.field_width--) { |
537 | if (buf < end) | 568 | if (buf < end) |
538 | *buf = ' '; | 569 | *buf = ' '; |
539 | ++buf; | 570 | ++buf; |
@@ -541,21 +572,24 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio | |||
541 | return buf; | 572 | return buf; |
542 | } | 573 | } |
543 | 574 | ||
544 | static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags) | 575 | static char *symbol_string(char *buf, char *end, void *ptr, |
576 | struct printf_spec spec) | ||
545 | { | 577 | { |
546 | unsigned long value = (unsigned long) ptr; | 578 | unsigned long value = (unsigned long) ptr; |
547 | #ifdef CONFIG_KALLSYMS | 579 | #ifdef CONFIG_KALLSYMS |
548 | char sym[KSYM_SYMBOL_LEN]; | 580 | char sym[KSYM_SYMBOL_LEN]; |
549 | sprint_symbol(sym, value); | 581 | sprint_symbol(sym, value); |
550 | return string(buf, end, sym, field_width, precision, flags); | 582 | return string(buf, end, sym, spec); |
551 | #else | 583 | #else |
552 | field_width = 2*sizeof(void *); | 584 | spec.field_width = 2*sizeof(void *); |
553 | flags |= SPECIAL | SMALL | ZEROPAD; | 585 | spec.flags |= SPECIAL | SMALL | ZEROPAD; |
554 | return number(buf, end, value, 16, field_width, precision, flags); | 586 | spec.base = 16; |
587 | return number(buf, end, value, spec); | ||
555 | #endif | 588 | #endif |
556 | } | 589 | } |
557 | 590 | ||
558 | static char *resource_string(char *buf, char *end, struct resource *res, int field_width, int precision, int flags) | 591 | static char *resource_string(char *buf, char *end, struct resource *res, |
592 | struct printf_spec spec) | ||
559 | { | 593 | { |
560 | #ifndef IO_RSRC_PRINTK_SIZE | 594 | #ifndef IO_RSRC_PRINTK_SIZE |
561 | #define IO_RSRC_PRINTK_SIZE 4 | 595 | #define IO_RSRC_PRINTK_SIZE 4 |
@@ -564,7 +598,11 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie | |||
564 | #ifndef MEM_RSRC_PRINTK_SIZE | 598 | #ifndef MEM_RSRC_PRINTK_SIZE |
565 | #define MEM_RSRC_PRINTK_SIZE 8 | 599 | #define MEM_RSRC_PRINTK_SIZE 8 |
566 | #endif | 600 | #endif |
567 | 601 | struct printf_spec num_spec = { | |
602 | .base = 16, | ||
603 | .precision = -1, | ||
604 | .flags = SPECIAL | SMALL | ZEROPAD, | ||
605 | }; | ||
568 | /* room for the actual numbers, the two "0x", -, [, ] and the final zero */ | 606 | /* room for the actual numbers, the two "0x", -, [, ] and the final zero */ |
569 | char sym[4*sizeof(resource_size_t) + 8]; | 607 | char sym[4*sizeof(resource_size_t) + 8]; |
570 | char *p = sym, *pend = sym + sizeof(sym); | 608 | char *p = sym, *pend = sym + sizeof(sym); |
@@ -576,17 +614,18 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie | |||
576 | size = MEM_RSRC_PRINTK_SIZE; | 614 | size = MEM_RSRC_PRINTK_SIZE; |
577 | 615 | ||
578 | *p++ = '['; | 616 | *p++ = '['; |
579 | p = number(p, pend, res->start, 16, size, -1, SPECIAL | SMALL | ZEROPAD); | 617 | num_spec.field_width = size; |
618 | p = number(p, pend, res->start, num_spec); | ||
580 | *p++ = '-'; | 619 | *p++ = '-'; |
581 | p = number(p, pend, res->end, 16, size, -1, SPECIAL | SMALL | ZEROPAD); | 620 | p = number(p, pend, res->end, num_spec); |
582 | *p++ = ']'; | 621 | *p++ = ']'; |
583 | *p = 0; | 622 | *p = 0; |
584 | 623 | ||
585 | return string(buf, end, sym, field_width, precision, flags); | 624 | return string(buf, end, sym, spec); |
586 | } | 625 | } |
587 | 626 | ||
588 | static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, | 627 | static char *mac_address_string(char *buf, char *end, u8 *addr, |
589 | int precision, int flags) | 628 | struct printf_spec spec) |
590 | { | 629 | { |
591 | char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ | 630 | char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ |
592 | char *p = mac_addr; | 631 | char *p = mac_addr; |
@@ -594,16 +633,17 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, | |||
594 | 633 | ||
595 | for (i = 0; i < 6; i++) { | 634 | for (i = 0; i < 6; i++) { |
596 | p = pack_hex_byte(p, addr[i]); | 635 | p = pack_hex_byte(p, addr[i]); |
597 | if (!(flags & SPECIAL) && i != 5) | 636 | if (!(spec.flags & SPECIAL) && i != 5) |
598 | *p++ = ':'; | 637 | *p++ = ':'; |
599 | } | 638 | } |
600 | *p = '\0'; | 639 | *p = '\0'; |
640 | spec.flags &= ~SPECIAL; | ||
601 | 641 | ||
602 | return string(buf, end, mac_addr, field_width, precision, flags & ~SPECIAL); | 642 | return string(buf, end, mac_addr, spec); |
603 | } | 643 | } |
604 | 644 | ||
605 | static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, | 645 | static char *ip6_addr_string(char *buf, char *end, u8 *addr, |
606 | int precision, int flags) | 646 | struct printf_spec spec) |
607 | { | 647 | { |
608 | char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ | 648 | char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ |
609 | char *p = ip6_addr; | 649 | char *p = ip6_addr; |
@@ -612,16 +652,17 @@ static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, | |||
612 | for (i = 0; i < 8; i++) { | 652 | for (i = 0; i < 8; i++) { |
613 | p = pack_hex_byte(p, addr[2 * i]); | 653 | p = pack_hex_byte(p, addr[2 * i]); |
614 | p = pack_hex_byte(p, addr[2 * i + 1]); | 654 | p = pack_hex_byte(p, addr[2 * i + 1]); |
615 | if (!(flags & SPECIAL) && i != 7) | 655 | if (!(spec.flags & SPECIAL) && i != 7) |
616 | *p++ = ':'; | 656 | *p++ = ':'; |
617 | } | 657 | } |
618 | *p = '\0'; | 658 | *p = '\0'; |
659 | spec.flags &= ~SPECIAL; | ||
619 | 660 | ||
620 | return string(buf, end, ip6_addr, field_width, precision, flags & ~SPECIAL); | 661 | return string(buf, end, ip6_addr, spec); |
621 | } | 662 | } |
622 | 663 | ||
623 | static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, | 664 | static char *ip4_addr_string(char *buf, char *end, u8 *addr, |
624 | int precision, int flags) | 665 | struct printf_spec spec) |
625 | { | 666 | { |
626 | char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ | 667 | char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ |
627 | char temp[3]; /* hold each IP quad in reverse order */ | 668 | char temp[3]; /* hold each IP quad in reverse order */ |
@@ -637,8 +678,9 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, | |||
637 | *p++ = '.'; | 678 | *p++ = '.'; |
638 | } | 679 | } |
639 | *p = '\0'; | 680 | *p = '\0'; |
681 | spec.flags &= ~SPECIAL; | ||
640 | 682 | ||
641 | return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); | 683 | return string(buf, end, ip4_addr, spec); |
642 | } | 684 | } |
643 | 685 | ||
644 | /* | 686 | /* |
@@ -663,41 +705,234 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, | |||
663 | * function pointers are really function descriptors, which contain a | 705 | * function pointers are really function descriptors, which contain a |
664 | * pointer to the real address. | 706 | * pointer to the real address. |
665 | */ | 707 | */ |
666 | static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags) | 708 | static char *pointer(const char *fmt, char *buf, char *end, void *ptr, |
709 | struct printf_spec spec) | ||
667 | { | 710 | { |
668 | if (!ptr) | 711 | if (!ptr) |
669 | return string(buf, end, "(null)", field_width, precision, flags); | 712 | return string(buf, end, "(null)", spec); |
670 | 713 | ||
671 | switch (*fmt) { | 714 | switch (*fmt) { |
672 | case 'F': | 715 | case 'F': |
673 | ptr = dereference_function_descriptor(ptr); | 716 | ptr = dereference_function_descriptor(ptr); |
674 | /* Fallthrough */ | 717 | /* Fallthrough */ |
675 | case 'S': | 718 | case 'S': |
676 | return symbol_string(buf, end, ptr, field_width, precision, flags); | 719 | return symbol_string(buf, end, ptr, spec); |
677 | case 'R': | 720 | case 'R': |
678 | return resource_string(buf, end, ptr, field_width, precision, flags); | 721 | return resource_string(buf, end, ptr, spec); |
679 | case 'm': | 722 | case 'm': |
680 | flags |= SPECIAL; | 723 | spec.flags |= SPECIAL; |
681 | /* Fallthrough */ | 724 | /* Fallthrough */ |
682 | case 'M': | 725 | case 'M': |
683 | return mac_address_string(buf, end, ptr, field_width, precision, flags); | 726 | return mac_address_string(buf, end, ptr, spec); |
684 | case 'i': | 727 | case 'i': |
685 | flags |= SPECIAL; | 728 | spec.flags |= SPECIAL; |
686 | /* Fallthrough */ | 729 | /* Fallthrough */ |
687 | case 'I': | 730 | case 'I': |
688 | if (fmt[1] == '6') | 731 | if (fmt[1] == '6') |
689 | return ip6_addr_string(buf, end, ptr, field_width, precision, flags); | 732 | return ip6_addr_string(buf, end, ptr, spec); |
690 | if (fmt[1] == '4') | 733 | if (fmt[1] == '4') |
691 | return ip4_addr_string(buf, end, ptr, field_width, precision, flags); | 734 | return ip4_addr_string(buf, end, ptr, spec); |
692 | flags &= ~SPECIAL; | 735 | spec.flags &= ~SPECIAL; |
736 | break; | ||
737 | } | ||
738 | spec.flags |= SMALL; | ||
739 | if (spec.field_width == -1) { | ||
740 | spec.field_width = 2*sizeof(void *); | ||
741 | spec.flags |= ZEROPAD; | ||
742 | } | ||
743 | spec.base = 16; | ||
744 | |||
745 | return number(buf, end, (unsigned long) ptr, spec); | ||
746 | } | ||
747 | |||
748 | /* | ||
749 | * Helper function to decode printf style format. | ||
750 | * Each call decode a token from the format and return the | ||
751 | * number of characters read (or likely the delta where it wants | ||
752 | * to go on the next call). | ||
753 | * The decoded token is returned through the parameters | ||
754 | * | ||
755 | * 'h', 'l', or 'L' for integer fields | ||
756 | * 'z' support added 23/7/1999 S.H. | ||
757 | * 'z' changed to 'Z' --davidm 1/25/99 | ||
758 | * 't' added for ptrdiff_t | ||
759 | * | ||
760 | * @fmt: the format string | ||
761 | * @type of the token returned | ||
762 | * @flags: various flags such as +, -, # tokens.. | ||
763 | * @field_width: overwritten width | ||
764 | * @base: base of the number (octal, hex, ...) | ||
765 | * @precision: precision of a number | ||
766 | * @qualifier: qualifier of a number (long, size_t, ...) | ||
767 | */ | ||
768 | static int format_decode(const char *fmt, struct printf_spec *spec) | ||
769 | { | ||
770 | const char *start = fmt; | ||
771 | bool sign = false; | ||
772 | |||
773 | /* we finished early by reading the field width */ | ||
774 | if (spec->type == FORMAT_TYPE_WITDH) { | ||
775 | if (spec->field_width < 0) { | ||
776 | spec->field_width = -spec->field_width; | ||
777 | spec->flags |= LEFT; | ||
778 | } | ||
779 | spec->type = FORMAT_TYPE_NONE; | ||
780 | goto precision; | ||
781 | } | ||
782 | |||
783 | /* we finished early by reading the precision */ | ||
784 | if (spec->type == FORMAT_TYPE_PRECISION) { | ||
785 | if (spec->precision < 0) | ||
786 | spec->precision = 0; | ||
787 | |||
788 | spec->type = FORMAT_TYPE_NONE; | ||
789 | goto qualifier; | ||
790 | } | ||
791 | |||
792 | /* By default */ | ||
793 | spec->type = FORMAT_TYPE_NONE; | ||
794 | |||
795 | for (; *fmt ; ++fmt) { | ||
796 | if (*fmt == '%') | ||
797 | break; | ||
798 | } | ||
799 | |||
800 | /* Return the current non-format string */ | ||
801 | if (fmt != start || !*fmt) | ||
802 | return fmt - start; | ||
803 | |||
804 | /* Process flags */ | ||
805 | spec->flags = 0; | ||
806 | |||
807 | while (1) { /* this also skips first '%' */ | ||
808 | bool found = true; | ||
809 | |||
810 | ++fmt; | ||
811 | |||
812 | switch (*fmt) { | ||
813 | case '-': spec->flags |= LEFT; break; | ||
814 | case '+': spec->flags |= PLUS; break; | ||
815 | case ' ': spec->flags |= SPACE; break; | ||
816 | case '#': spec->flags |= SPECIAL; break; | ||
817 | case '0': spec->flags |= ZEROPAD; break; | ||
818 | default: found = false; | ||
819 | } | ||
820 | |||
821 | if (!found) | ||
822 | break; | ||
823 | } | ||
824 | |||
825 | /* get field width */ | ||
826 | spec->field_width = -1; | ||
827 | |||
828 | if (isdigit(*fmt)) | ||
829 | spec->field_width = skip_atoi(&fmt); | ||
830 | else if (*fmt == '*') { | ||
831 | /* it's the next argument */ | ||
832 | spec->type = FORMAT_TYPE_WITDH; | ||
833 | return ++fmt - start; | ||
834 | } | ||
835 | |||
836 | precision: | ||
837 | /* get the precision */ | ||
838 | spec->precision = -1; | ||
839 | if (*fmt == '.') { | ||
840 | ++fmt; | ||
841 | if (isdigit(*fmt)) { | ||
842 | spec->precision = skip_atoi(&fmt); | ||
843 | if (spec->precision < 0) | ||
844 | spec->precision = 0; | ||
845 | } else if (*fmt == '*') { | ||
846 | /* it's the next argument */ | ||
847 | spec->type = FORMAT_TYPE_WITDH; | ||
848 | return ++fmt - start; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | qualifier: | ||
853 | /* get the conversion qualifier */ | ||
854 | spec->qualifier = -1; | ||
855 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || | ||
856 | *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { | ||
857 | spec->qualifier = *fmt; | ||
858 | ++fmt; | ||
859 | if (spec->qualifier == 'l' && *fmt == 'l') { | ||
860 | spec->qualifier = 'L'; | ||
861 | ++fmt; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | /* default base */ | ||
866 | spec->base = 10; | ||
867 | switch (*fmt) { | ||
868 | case 'c': | ||
869 | spec->type = FORMAT_TYPE_CHAR; | ||
870 | return ++fmt - start; | ||
871 | |||
872 | case 's': | ||
873 | spec->type = FORMAT_TYPE_STR; | ||
874 | return ++fmt - start; | ||
875 | |||
876 | case 'p': | ||
877 | spec->type = FORMAT_TYPE_PTR; | ||
878 | return fmt - start; | ||
879 | /* skip alnum */ | ||
880 | |||
881 | case 'n': | ||
882 | spec->type = FORMAT_TYPE_NRCHARS; | ||
883 | return ++fmt - start; | ||
884 | |||
885 | case '%': | ||
886 | spec->type = FORMAT_TYPE_PERCENT_CHAR; | ||
887 | return ++fmt - start; | ||
888 | |||
889 | /* integer number formats - set up the flags and "break" */ | ||
890 | case 'o': | ||
891 | spec->base = 8; | ||
892 | break; | ||
893 | |||
894 | case 'x': | ||
895 | spec->flags |= SMALL; | ||
896 | |||
897 | case 'X': | ||
898 | spec->base = 16; | ||
899 | break; | ||
900 | |||
901 | case 'd': | ||
902 | case 'i': | ||
903 | sign = true; | ||
904 | case 'u': | ||
693 | break; | 905 | break; |
906 | |||
907 | default: | ||
908 | spec->type = FORMAT_TYPE_INVALID; | ||
909 | return fmt - start; | ||
694 | } | 910 | } |
695 | flags |= SMALL; | 911 | |
696 | if (field_width == -1) { | 912 | if (spec->qualifier == 'L') |
697 | field_width = 2*sizeof(void *); | 913 | spec->type = FORMAT_TYPE_LONG_LONG; |
698 | flags |= ZEROPAD; | 914 | else if (spec->qualifier == 'l') { |
915 | if (sign) | ||
916 | spec->type = FORMAT_TYPE_LONG; | ||
917 | else | ||
918 | spec->type = FORMAT_TYPE_ULONG; | ||
919 | } else if (spec->qualifier == 'Z' || spec->qualifier == 'z') { | ||
920 | spec->type = FORMAT_TYPE_SIZE_T; | ||
921 | } else if (spec->qualifier == 't') { | ||
922 | spec->type = FORMAT_TYPE_PTRDIFF; | ||
923 | } else if (spec->qualifier == 'h') { | ||
924 | if (sign) | ||
925 | spec->type = FORMAT_TYPE_SHORT; | ||
926 | else | ||
927 | spec->type = FORMAT_TYPE_USHORT; | ||
928 | } else { | ||
929 | if (sign) | ||
930 | spec->type = FORMAT_TYPE_INT; | ||
931 | else | ||
932 | spec->type = FORMAT_TYPE_UINT; | ||
699 | } | 933 | } |
700 | return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags); | 934 | |
935 | return ++fmt - start; | ||
701 | } | 936 | } |
702 | 937 | ||
703 | /** | 938 | /** |
@@ -726,18 +961,9 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field | |||
726 | int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | 961 | int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) |
727 | { | 962 | { |
728 | unsigned long long num; | 963 | unsigned long long num; |
729 | int base; | ||
730 | char *str, *end, c; | 964 | char *str, *end, c; |
731 | 965 | int read; | |
732 | int flags; /* flags to number() */ | 966 | struct printf_spec spec = {0}; |
733 | |||
734 | int field_width; /* width of output field */ | ||
735 | int precision; /* min. # of digits for integers; max | ||
736 | number of chars for from string */ | ||
737 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ | ||
738 | /* 'z' support added 23/7/1999 S.H. */ | ||
739 | /* 'z' changed to 'Z' --davidm 1/25/99 */ | ||
740 | /* 't' added for ptrdiff_t */ | ||
741 | 967 | ||
742 | /* Reject out-of-range values early. Large positive sizes are | 968 | /* Reject out-of-range values early. Large positive sizes are |
743 | used for unknown buffer sizes. */ | 969 | used for unknown buffer sizes. */ |
@@ -758,184 +984,144 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
758 | size = end - buf; | 984 | size = end - buf; |
759 | } | 985 | } |
760 | 986 | ||
761 | for (; *fmt ; ++fmt) { | 987 | while (*fmt) { |
762 | if (*fmt != '%') { | 988 | const char *old_fmt = fmt; |
763 | if (str < end) | ||
764 | *str = *fmt; | ||
765 | ++str; | ||
766 | continue; | ||
767 | } | ||
768 | 989 | ||
769 | /* process flags */ | 990 | read = format_decode(fmt, &spec); |
770 | flags = 0; | ||
771 | repeat: | ||
772 | ++fmt; /* this also skips first '%' */ | ||
773 | switch (*fmt) { | ||
774 | case '-': flags |= LEFT; goto repeat; | ||
775 | case '+': flags |= PLUS; goto repeat; | ||
776 | case ' ': flags |= SPACE; goto repeat; | ||
777 | case '#': flags |= SPECIAL; goto repeat; | ||
778 | case '0': flags |= ZEROPAD; goto repeat; | ||
779 | } | ||
780 | 991 | ||
781 | /* get field width */ | 992 | fmt += read; |
782 | field_width = -1; | ||
783 | if (isdigit(*fmt)) | ||
784 | field_width = skip_atoi(&fmt); | ||
785 | else if (*fmt == '*') { | ||
786 | ++fmt; | ||
787 | /* it's the next argument */ | ||
788 | field_width = va_arg(args, int); | ||
789 | if (field_width < 0) { | ||
790 | field_width = -field_width; | ||
791 | flags |= LEFT; | ||
792 | } | ||
793 | } | ||
794 | 993 | ||
795 | /* get the precision */ | 994 | switch (spec.type) { |
796 | precision = -1; | 995 | case FORMAT_TYPE_NONE: { |
797 | if (*fmt == '.') { | 996 | int copy = read; |
798 | ++fmt; | 997 | if (str < end) { |
799 | if (isdigit(*fmt)) | 998 | if (copy > end - str) |
800 | precision = skip_atoi(&fmt); | 999 | copy = end - str; |
801 | else if (*fmt == '*') { | 1000 | memcpy(str, old_fmt, copy); |
802 | ++fmt; | ||
803 | /* it's the next argument */ | ||
804 | precision = va_arg(args, int); | ||
805 | } | 1001 | } |
806 | if (precision < 0) | 1002 | str += read; |
807 | precision = 0; | 1003 | break; |
808 | } | 1004 | } |
809 | 1005 | ||
810 | /* get the conversion qualifier */ | 1006 | case FORMAT_TYPE_WITDH: |
811 | qualifier = -1; | 1007 | spec.field_width = va_arg(args, int); |
812 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || | 1008 | break; |
813 | *fmt =='Z' || *fmt == 'z' || *fmt == 't') { | ||
814 | qualifier = *fmt; | ||
815 | ++fmt; | ||
816 | if (qualifier == 'l' && *fmt == 'l') { | ||
817 | qualifier = 'L'; | ||
818 | ++fmt; | ||
819 | } | ||
820 | } | ||
821 | 1009 | ||
822 | /* default base */ | 1010 | case FORMAT_TYPE_PRECISION: |
823 | base = 10; | 1011 | spec.precision = va_arg(args, int); |
1012 | break; | ||
824 | 1013 | ||
825 | switch (*fmt) { | 1014 | case FORMAT_TYPE_CHAR: |
826 | case 'c': | 1015 | if (!(spec.flags & LEFT)) { |
827 | if (!(flags & LEFT)) { | 1016 | while (--spec.field_width > 0) { |
828 | while (--field_width > 0) { | ||
829 | if (str < end) | ||
830 | *str = ' '; | ||
831 | ++str; | ||
832 | } | ||
833 | } | ||
834 | c = (unsigned char) va_arg(args, int); | ||
835 | if (str < end) | ||
836 | *str = c; | ||
837 | ++str; | ||
838 | while (--field_width > 0) { | ||
839 | if (str < end) | 1017 | if (str < end) |
840 | *str = ' '; | 1018 | *str = ' '; |
841 | ++str; | 1019 | ++str; |
842 | } | ||
843 | continue; | ||
844 | |||
845 | case 's': | ||
846 | str = string(str, end, va_arg(args, char *), field_width, precision, flags); | ||
847 | continue; | ||
848 | |||
849 | case 'p': | ||
850 | str = pointer(fmt+1, str, end, | ||
851 | va_arg(args, void *), | ||
852 | field_width, precision, flags); | ||
853 | /* Skip all alphanumeric pointer suffixes */ | ||
854 | while (isalnum(fmt[1])) | ||
855 | fmt++; | ||
856 | continue; | ||
857 | |||
858 | case 'n': | ||
859 | /* FIXME: | ||
860 | * What does C99 say about the overflow case here? */ | ||
861 | if (qualifier == 'l') { | ||
862 | long * ip = va_arg(args, long *); | ||
863 | *ip = (str - buf); | ||
864 | } else if (qualifier == 'Z' || qualifier == 'z') { | ||
865 | size_t * ip = va_arg(args, size_t *); | ||
866 | *ip = (str - buf); | ||
867 | } else { | ||
868 | int * ip = va_arg(args, int *); | ||
869 | *ip = (str - buf); | ||
870 | } | ||
871 | continue; | ||
872 | 1020 | ||
873 | case '%': | 1021 | } |
1022 | } | ||
1023 | c = (unsigned char) va_arg(args, int); | ||
1024 | if (str < end) | ||
1025 | *str = c; | ||
1026 | ++str; | ||
1027 | while (--spec.field_width > 0) { | ||
874 | if (str < end) | 1028 | if (str < end) |
875 | *str = '%'; | 1029 | *str = ' '; |
876 | ++str; | 1030 | ++str; |
877 | continue; | 1031 | } |
1032 | break; | ||
878 | 1033 | ||
879 | /* integer number formats - set up the flags and "break" */ | 1034 | case FORMAT_TYPE_STR: |
880 | case 'o': | 1035 | str = string(str, end, va_arg(args, char *), spec); |
881 | base = 8; | 1036 | break; |
882 | break; | ||
883 | 1037 | ||
884 | case 'x': | 1038 | case FORMAT_TYPE_PTR: |
885 | flags |= SMALL; | 1039 | str = pointer(fmt+1, str, end, va_arg(args, void *), |
886 | case 'X': | 1040 | spec); |
887 | base = 16; | 1041 | while (isalnum(*fmt)) |
888 | break; | 1042 | fmt++; |
1043 | break; | ||
889 | 1044 | ||
890 | case 'd': | 1045 | case FORMAT_TYPE_PERCENT_CHAR: |
891 | case 'i': | 1046 | if (str < end) |
892 | flags |= SIGN; | 1047 | *str = '%'; |
893 | case 'u': | 1048 | ++str; |
894 | break; | 1049 | break; |
895 | 1050 | ||
896 | default: | 1051 | case FORMAT_TYPE_INVALID: |
1052 | if (str < end) | ||
1053 | *str = '%'; | ||
1054 | ++str; | ||
1055 | if (*fmt) { | ||
897 | if (str < end) | 1056 | if (str < end) |
898 | *str = '%'; | 1057 | *str = *fmt; |
899 | ++str; | 1058 | ++str; |
900 | if (*fmt) { | 1059 | } else { |
901 | if (str < end) | 1060 | --fmt; |
902 | *str = *fmt; | 1061 | } |
903 | ++str; | 1062 | break; |
904 | } else { | 1063 | |
905 | --fmt; | 1064 | case FORMAT_TYPE_NRCHARS: { |
906 | } | 1065 | int qualifier = spec.qualifier; |
907 | continue; | 1066 | |
1067 | if (qualifier == 'l') { | ||
1068 | long *ip = va_arg(args, long *); | ||
1069 | *ip = (str - buf); | ||
1070 | } else if (qualifier == 'Z' || | ||
1071 | qualifier == 'z') { | ||
1072 | size_t *ip = va_arg(args, size_t *); | ||
1073 | *ip = (str - buf); | ||
1074 | } else { | ||
1075 | int *ip = va_arg(args, int *); | ||
1076 | *ip = (str - buf); | ||
1077 | } | ||
1078 | break; | ||
908 | } | 1079 | } |
909 | if (qualifier == 'L') | 1080 | |
910 | num = va_arg(args, long long); | 1081 | default: |
911 | else if (qualifier == 'l') { | 1082 | switch (spec.type) { |
912 | num = va_arg(args, unsigned long); | 1083 | case FORMAT_TYPE_LONG_LONG: |
913 | if (flags & SIGN) | 1084 | num = va_arg(args, long long); |
914 | num = (signed long) num; | 1085 | break; |
915 | } else if (qualifier == 'Z' || qualifier == 'z') { | 1086 | case FORMAT_TYPE_ULONG: |
916 | num = va_arg(args, size_t); | 1087 | num = va_arg(args, unsigned long); |
917 | } else if (qualifier == 't') { | 1088 | break; |
918 | num = va_arg(args, ptrdiff_t); | 1089 | case FORMAT_TYPE_LONG: |
919 | } else if (qualifier == 'h') { | 1090 | num = va_arg(args, long); |
920 | num = (unsigned short) va_arg(args, int); | 1091 | break; |
921 | if (flags & SIGN) | 1092 | case FORMAT_TYPE_SIZE_T: |
922 | num = (signed short) num; | 1093 | num = va_arg(args, size_t); |
923 | } else { | 1094 | break; |
924 | num = va_arg(args, unsigned int); | 1095 | case FORMAT_TYPE_PTRDIFF: |
925 | if (flags & SIGN) | 1096 | num = va_arg(args, ptrdiff_t); |
926 | num = (signed int) num; | 1097 | break; |
1098 | case FORMAT_TYPE_USHORT: | ||
1099 | num = (unsigned short) va_arg(args, int); | ||
1100 | break; | ||
1101 | case FORMAT_TYPE_SHORT: | ||
1102 | num = (short) va_arg(args, int); | ||
1103 | break; | ||
1104 | case FORMAT_TYPE_UINT: | ||
1105 | num = va_arg(args, unsigned int); | ||
1106 | break; | ||
1107 | default: | ||
1108 | num = va_arg(args, unsigned int); | ||
1109 | } | ||
1110 | |||
1111 | str = number(str, end, num, spec); | ||
927 | } | 1112 | } |
928 | str = number(str, end, num, base, | ||
929 | field_width, precision, flags); | ||
930 | } | 1113 | } |
1114 | |||
931 | if (size > 0) { | 1115 | if (size > 0) { |
932 | if (str < end) | 1116 | if (str < end) |
933 | *str = '\0'; | 1117 | *str = '\0'; |
934 | else | 1118 | else |
935 | end[-1] = '\0'; | 1119 | end[-1] = '\0'; |
936 | } | 1120 | } |
1121 | |||
937 | /* the trailing null byte doesn't count towards the total */ | 1122 | /* the trailing null byte doesn't count towards the total */ |
938 | return str-buf; | 1123 | return str-buf; |
1124 | |||
939 | } | 1125 | } |
940 | EXPORT_SYMBOL(vsnprintf); | 1126 | EXPORT_SYMBOL(vsnprintf); |
941 | 1127 | ||
@@ -1058,6 +1244,372 @@ int sprintf(char * buf, const char *fmt, ...) | |||
1058 | } | 1244 | } |
1059 | EXPORT_SYMBOL(sprintf); | 1245 | EXPORT_SYMBOL(sprintf); |
1060 | 1246 | ||
1247 | #ifdef CONFIG_BINARY_PRINTF | ||
1248 | /* | ||
1249 | * bprintf service: | ||
1250 | * vbin_printf() - VA arguments to binary data | ||
1251 | * bstr_printf() - Binary data to text string | ||
1252 | */ | ||
1253 | |||
1254 | /** | ||
1255 | * vbin_printf - Parse a format string and place args' binary value in a buffer | ||
1256 | * @bin_buf: The buffer to place args' binary value | ||
1257 | * @size: The size of the buffer(by words(32bits), not characters) | ||
1258 | * @fmt: The format string to use | ||
1259 | * @args: Arguments for the format string | ||
1260 | * | ||
1261 | * The format follows C99 vsnprintf, except %n is ignored, and its argument | ||
1262 | * is skiped. | ||
1263 | * | ||
1264 | * The return value is the number of words(32bits) which would be generated for | ||
1265 | * the given input. | ||
1266 | * | ||
1267 | * NOTE: | ||
1268 | * If the return value is greater than @size, the resulting bin_buf is NOT | ||
1269 | * valid for bstr_printf(). | ||
1270 | */ | ||
1271 | int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) | ||
1272 | { | ||
1273 | struct printf_spec spec = {0}; | ||
1274 | char *str, *end; | ||
1275 | int read; | ||
1276 | |||
1277 | str = (char *)bin_buf; | ||
1278 | end = (char *)(bin_buf + size); | ||
1279 | |||
1280 | #define save_arg(type) \ | ||
1281 | do { \ | ||
1282 | if (sizeof(type) == 8) { \ | ||
1283 | unsigned long long value; \ | ||
1284 | str = PTR_ALIGN(str, sizeof(u32)); \ | ||
1285 | value = va_arg(args, unsigned long long); \ | ||
1286 | if (str + sizeof(type) <= end) { \ | ||
1287 | *(u32 *)str = *(u32 *)&value; \ | ||
1288 | *(u32 *)(str + 4) = *((u32 *)&value + 1); \ | ||
1289 | } \ | ||
1290 | } else { \ | ||
1291 | unsigned long value; \ | ||
1292 | str = PTR_ALIGN(str, sizeof(type)); \ | ||
1293 | value = va_arg(args, int); \ | ||
1294 | if (str + sizeof(type) <= end) \ | ||
1295 | *(typeof(type) *)str = (type)value; \ | ||
1296 | } \ | ||
1297 | str += sizeof(type); \ | ||
1298 | } while (0) | ||
1299 | |||
1300 | |||
1301 | while (*fmt) { | ||
1302 | read = format_decode(fmt, &spec); | ||
1303 | |||
1304 | fmt += read; | ||
1305 | |||
1306 | switch (spec.type) { | ||
1307 | case FORMAT_TYPE_NONE: | ||
1308 | break; | ||
1309 | |||
1310 | case FORMAT_TYPE_WITDH: | ||
1311 | case FORMAT_TYPE_PRECISION: | ||
1312 | save_arg(int); | ||
1313 | break; | ||
1314 | |||
1315 | case FORMAT_TYPE_CHAR: | ||
1316 | save_arg(char); | ||
1317 | break; | ||
1318 | |||
1319 | case FORMAT_TYPE_STR: { | ||
1320 | const char *save_str = va_arg(args, char *); | ||
1321 | size_t len; | ||
1322 | if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE | ||
1323 | || (unsigned long)save_str < PAGE_SIZE) | ||
1324 | save_str = "<NULL>"; | ||
1325 | len = strlen(save_str); | ||
1326 | if (str + len + 1 < end) | ||
1327 | memcpy(str, save_str, len + 1); | ||
1328 | str += len + 1; | ||
1329 | break; | ||
1330 | } | ||
1331 | |||
1332 | case FORMAT_TYPE_PTR: | ||
1333 | save_arg(void *); | ||
1334 | /* skip all alphanumeric pointer suffixes */ | ||
1335 | while (isalnum(*fmt)) | ||
1336 | fmt++; | ||
1337 | break; | ||
1338 | |||
1339 | case FORMAT_TYPE_PERCENT_CHAR: | ||
1340 | break; | ||
1341 | |||
1342 | case FORMAT_TYPE_INVALID: | ||
1343 | if (!*fmt) | ||
1344 | --fmt; | ||
1345 | break; | ||
1346 | |||
1347 | case FORMAT_TYPE_NRCHARS: { | ||
1348 | /* skip %n 's argument */ | ||
1349 | int qualifier = spec.qualifier; | ||
1350 | void *skip_arg; | ||
1351 | if (qualifier == 'l') | ||
1352 | skip_arg = va_arg(args, long *); | ||
1353 | else if (qualifier == 'Z' || qualifier == 'z') | ||
1354 | skip_arg = va_arg(args, size_t *); | ||
1355 | else | ||
1356 | skip_arg = va_arg(args, int *); | ||
1357 | break; | ||
1358 | } | ||
1359 | |||
1360 | default: | ||
1361 | switch (spec.type) { | ||
1362 | |||
1363 | case FORMAT_TYPE_LONG_LONG: | ||
1364 | save_arg(long long); | ||
1365 | break; | ||
1366 | case FORMAT_TYPE_ULONG: | ||
1367 | case FORMAT_TYPE_LONG: | ||
1368 | save_arg(unsigned long); | ||
1369 | break; | ||
1370 | case FORMAT_TYPE_SIZE_T: | ||
1371 | save_arg(size_t); | ||
1372 | break; | ||
1373 | case FORMAT_TYPE_PTRDIFF: | ||
1374 | save_arg(ptrdiff_t); | ||
1375 | break; | ||
1376 | case FORMAT_TYPE_USHORT: | ||
1377 | case FORMAT_TYPE_SHORT: | ||
1378 | save_arg(short); | ||
1379 | break; | ||
1380 | default: | ||
1381 | save_arg(int); | ||
1382 | } | ||
1383 | } | ||
1384 | } | ||
1385 | return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf; | ||
1386 | |||
1387 | #undef save_arg | ||
1388 | } | ||
1389 | EXPORT_SYMBOL_GPL(vbin_printf); | ||
1390 | |||
1391 | /** | ||
1392 | * bstr_printf - Format a string from binary arguments and place it in a buffer | ||
1393 | * @buf: The buffer to place the result into | ||
1394 | * @size: The size of the buffer, including the trailing null space | ||
1395 | * @fmt: The format string to use | ||
1396 | * @bin_buf: Binary arguments for the format string | ||
1397 | * | ||
1398 | * This function like C99 vsnprintf, but the difference is that vsnprintf gets | ||
1399 | * arguments from stack, and bstr_printf gets arguments from @bin_buf which is | ||
1400 | * a binary buffer that generated by vbin_printf. | ||
1401 | * | ||
1402 | * The format follows C99 vsnprintf, but has some extensions: | ||
1403 | * %pS output the name of a text symbol | ||
1404 | * %pF output the name of a function pointer | ||
1405 | * %pR output the address range in a struct resource | ||
1406 | * %n is ignored | ||
1407 | * | ||
1408 | * The return value is the number of characters which would | ||
1409 | * be generated for the given input, excluding the trailing | ||
1410 | * '\0', as per ISO C99. If you want to have the exact | ||
1411 | * number of characters written into @buf as return value | ||
1412 | * (not including the trailing '\0'), use vscnprintf(). If the | ||
1413 | * return is greater than or equal to @size, the resulting | ||
1414 | * string is truncated. | ||
1415 | */ | ||
1416 | int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) | ||
1417 | { | ||
1418 | unsigned long long num; | ||
1419 | char *str, *end, c; | ||
1420 | const char *args = (const char *)bin_buf; | ||
1421 | |||
1422 | struct printf_spec spec = {0}; | ||
1423 | |||
1424 | if (unlikely((int) size < 0)) { | ||
1425 | /* There can be only one.. */ | ||
1426 | static char warn = 1; | ||
1427 | WARN_ON(warn); | ||
1428 | warn = 0; | ||
1429 | return 0; | ||
1430 | } | ||
1431 | |||
1432 | str = buf; | ||
1433 | end = buf + size; | ||
1434 | |||
1435 | #define get_arg(type) \ | ||
1436 | ({ \ | ||
1437 | typeof(type) value; \ | ||
1438 | if (sizeof(type) == 8) { \ | ||
1439 | args = PTR_ALIGN(args, sizeof(u32)); \ | ||
1440 | *(u32 *)&value = *(u32 *)args; \ | ||
1441 | *((u32 *)&value + 1) = *(u32 *)(args + 4); \ | ||
1442 | } else { \ | ||
1443 | args = PTR_ALIGN(args, sizeof(type)); \ | ||
1444 | value = *(typeof(type) *)args; \ | ||
1445 | } \ | ||
1446 | args += sizeof(type); \ | ||
1447 | value; \ | ||
1448 | }) | ||
1449 | |||
1450 | /* Make sure end is always >= buf */ | ||
1451 | if (end < buf) { | ||
1452 | end = ((void *)-1); | ||
1453 | size = end - buf; | ||
1454 | } | ||
1455 | |||
1456 | while (*fmt) { | ||
1457 | int read; | ||
1458 | const char *old_fmt = fmt; | ||
1459 | |||
1460 | read = format_decode(fmt, &spec); | ||
1461 | |||
1462 | fmt += read; | ||
1463 | |||
1464 | switch (spec.type) { | ||
1465 | case FORMAT_TYPE_NONE: { | ||
1466 | int copy = read; | ||
1467 | if (str < end) { | ||
1468 | if (copy > end - str) | ||
1469 | copy = end - str; | ||
1470 | memcpy(str, old_fmt, copy); | ||
1471 | } | ||
1472 | str += read; | ||
1473 | break; | ||
1474 | } | ||
1475 | |||
1476 | case FORMAT_TYPE_WITDH: | ||
1477 | spec.field_width = get_arg(int); | ||
1478 | break; | ||
1479 | |||
1480 | case FORMAT_TYPE_PRECISION: | ||
1481 | spec.precision = get_arg(int); | ||
1482 | break; | ||
1483 | |||
1484 | case FORMAT_TYPE_CHAR: | ||
1485 | if (!(spec.flags & LEFT)) { | ||
1486 | while (--spec.field_width > 0) { | ||
1487 | if (str < end) | ||
1488 | *str = ' '; | ||
1489 | ++str; | ||
1490 | } | ||
1491 | } | ||
1492 | c = (unsigned char) get_arg(char); | ||
1493 | if (str < end) | ||
1494 | *str = c; | ||
1495 | ++str; | ||
1496 | while (--spec.field_width > 0) { | ||
1497 | if (str < end) | ||
1498 | *str = ' '; | ||
1499 | ++str; | ||
1500 | } | ||
1501 | break; | ||
1502 | |||
1503 | case FORMAT_TYPE_STR: { | ||
1504 | const char *str_arg = args; | ||
1505 | size_t len = strlen(str_arg); | ||
1506 | args += len + 1; | ||
1507 | str = string(str, end, (char *)str_arg, spec); | ||
1508 | break; | ||
1509 | } | ||
1510 | |||
1511 | case FORMAT_TYPE_PTR: | ||
1512 | str = pointer(fmt+1, str, end, get_arg(void *), spec); | ||
1513 | while (isalnum(*fmt)) | ||
1514 | fmt++; | ||
1515 | break; | ||
1516 | |||
1517 | case FORMAT_TYPE_PERCENT_CHAR: | ||
1518 | if (str < end) | ||
1519 | *str = '%'; | ||
1520 | ++str; | ||
1521 | break; | ||
1522 | |||
1523 | case FORMAT_TYPE_INVALID: | ||
1524 | if (str < end) | ||
1525 | *str = '%'; | ||
1526 | ++str; | ||
1527 | if (*fmt) { | ||
1528 | if (str < end) | ||
1529 | *str = *fmt; | ||
1530 | ++str; | ||
1531 | } else { | ||
1532 | --fmt; | ||
1533 | } | ||
1534 | break; | ||
1535 | |||
1536 | case FORMAT_TYPE_NRCHARS: | ||
1537 | /* skip */ | ||
1538 | break; | ||
1539 | |||
1540 | default: | ||
1541 | switch (spec.type) { | ||
1542 | |||
1543 | case FORMAT_TYPE_LONG_LONG: | ||
1544 | num = get_arg(long long); | ||
1545 | break; | ||
1546 | case FORMAT_TYPE_ULONG: | ||
1547 | num = get_arg(unsigned long); | ||
1548 | break; | ||
1549 | case FORMAT_TYPE_LONG: | ||
1550 | num = get_arg(unsigned long); | ||
1551 | break; | ||
1552 | case FORMAT_TYPE_SIZE_T: | ||
1553 | num = get_arg(size_t); | ||
1554 | break; | ||
1555 | case FORMAT_TYPE_PTRDIFF: | ||
1556 | num = get_arg(ptrdiff_t); | ||
1557 | break; | ||
1558 | case FORMAT_TYPE_USHORT: | ||
1559 | num = get_arg(unsigned short); | ||
1560 | break; | ||
1561 | case FORMAT_TYPE_SHORT: | ||
1562 | num = get_arg(short); | ||
1563 | break; | ||
1564 | case FORMAT_TYPE_UINT: | ||
1565 | num = get_arg(unsigned int); | ||
1566 | break; | ||
1567 | default: | ||
1568 | num = get_arg(int); | ||
1569 | } | ||
1570 | |||
1571 | str = number(str, end, num, spec); | ||
1572 | } | ||
1573 | } | ||
1574 | |||
1575 | if (size > 0) { | ||
1576 | if (str < end) | ||
1577 | *str = '\0'; | ||
1578 | else | ||
1579 | end[-1] = '\0'; | ||
1580 | } | ||
1581 | |||
1582 | #undef get_arg | ||
1583 | |||
1584 | /* the trailing null byte doesn't count towards the total */ | ||
1585 | return str - buf; | ||
1586 | } | ||
1587 | EXPORT_SYMBOL_GPL(bstr_printf); | ||
1588 | |||
1589 | /** | ||
1590 | * bprintf - Parse a format string and place args' binary value in a buffer | ||
1591 | * @bin_buf: The buffer to place args' binary value | ||
1592 | * @size: The size of the buffer(by words(32bits), not characters) | ||
1593 | * @fmt: The format string to use | ||
1594 | * @...: Arguments for the format string | ||
1595 | * | ||
1596 | * The function returns the number of words(u32) written | ||
1597 | * into @bin_buf. | ||
1598 | */ | ||
1599 | int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) | ||
1600 | { | ||
1601 | va_list args; | ||
1602 | int ret; | ||
1603 | |||
1604 | va_start(args, fmt); | ||
1605 | ret = vbin_printf(bin_buf, size, fmt, args); | ||
1606 | va_end(args); | ||
1607 | return ret; | ||
1608 | } | ||
1609 | EXPORT_SYMBOL_GPL(bprintf); | ||
1610 | |||
1611 | #endif /* CONFIG_BINARY_PRINTF */ | ||
1612 | |||
1061 | /** | 1613 | /** |
1062 | * vsscanf - Unformat a buffer into a list of arguments | 1614 | * vsscanf - Unformat a buffer into a list of arguments |
1063 | * @buf: input buffer | 1615 | * @buf: input buffer |