1 /* 2 * trace binary printk 3 * 4 * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com> 5 * 6 */ 7 #include <linux/seq_file.h> 8 #include <linux/debugfs.h> 9 #include <linux/uaccess.h> 10 #include <linux/kernel.h> 11 #include <linux/ftrace.h> 12 #include <linux/string.h> 13 #include <linux/module.h> 14 #include <linux/mutex.h> 15 #include <linux/ctype.h> 16 #include <linux/list.h> 17 #include <linux/slab.h> 18 #include <linux/fs.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_bprintk(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_vbprintk(ip, fmt, ap); 115 va_end(ap); 116 return ret; 117 } 118 EXPORT_SYMBOL_GPL(__trace_bprintk); 119 120 int __ftrace_vbprintk(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_vbprintk(ip, fmt, ap); 129 } 130 EXPORT_SYMBOL_GPL(__ftrace_vbprintk); 131 132 int __trace_printk(unsigned long ip, const char *fmt, ...) 133 { 134 int ret; 135 va_list ap; 136 137 if (!(trace_flags & TRACE_ITER_PRINTK)) 138 return 0; 139 140 va_start(ap, fmt); 141 ret = trace_vprintk(ip, fmt, ap); 142 va_end(ap); 143 return ret; 144 } 145 EXPORT_SYMBOL_GPL(__trace_printk); 146 147 int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) 148 { 149 if (!(trace_flags & TRACE_ITER_PRINTK)) 150 return 0; 151 152 return trace_vprintk(ip, fmt, ap); 153 } 154 EXPORT_SYMBOL_GPL(__ftrace_vprintk); 155 156 static void * 157 t_start(struct seq_file *m, loff_t *pos) 158 { 159 const char **fmt = __start___trace_bprintk_fmt + *pos; 160 161 if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt) 162 return NULL; 163 return fmt; 164 } 165 166 static void *t_next(struct seq_file *m, void * v, loff_t *pos) 167 { 168 (*pos)++; 169 return t_start(m, pos); 170 } 171 172 static int t_show(struct seq_file *m, void *v) 173 { 174 const char **fmt = v; 175 const char *str = *fmt; 176 int i; 177 178 seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); 179 180 /* 181 * Tabs and new lines need to be converted. 182 */ 183 for (i = 0; str[i]; i++) { 184 switch (str[i]) { 185 case '\n': 186 seq_puts(m, "\\n"); 187 break; 188 case '\t': 189 seq_puts(m, "\\t"); 190 break; 191 case '\\': 192 seq_puts(m, "\\"); 193 break; 194 case '"': 195 seq_puts(m, "\\\""); 196 break; 197 default: 198 seq_putc(m, str[i]); 199 } 200 } 201 seq_puts(m, "\"\n"); 202 203 return 0; 204 } 205 206 static void t_stop(struct seq_file *m, void *p) 207 { 208 } 209 210 static const struct seq_operations show_format_seq_ops = { 211 .start = t_start, 212 .next = t_next, 213 .show = t_show, 214 .stop = t_stop, 215 }; 216 217 static int 218 ftrace_formats_open(struct inode *inode, struct file *file) 219 { 220 return seq_open(file, &show_format_seq_ops); 221 } 222 223 static const struct file_operations ftrace_formats_fops = { 224 .open = ftrace_formats_open, 225 .read = seq_read, 226 .llseek = seq_lseek, 227 .release = seq_release, 228 }; 229 230 static __init int init_trace_printk_function_export(void) 231 { 232 struct dentry *d_tracer; 233 234 d_tracer = tracing_init_dentry(); 235 if (!d_tracer) 236 return 0; 237 238 trace_create_file("printk_formats", 0444, d_tracer, 239 NULL, &ftrace_formats_fops); 240 241 return 0; 242 } 243 244 fs_initcall(init_trace_printk_function_export); 245 246 static __init int init_trace_printk(void) 247 { 248 return register_module_notifier(&module_trace_bprintk_format_nb); 249 } 250 251 early_initcall(init_trace_printk); 252