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 |
