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/marker.h> 15 #include <linux/mutex.h> 16 #include <linux/ctype.h> 17 #include <linux/list.h> 18 #include <linux/slab.h> 19 #include <linux/fs.h> 20 21 #include "trace.h" 22 23 #ifdef CONFIG_MODULES 24 25 /* 26 * modules trace_printk()'s formats are autosaved in struct trace_bprintk_fmt 27 * which are queued on trace_bprintk_fmt_list. 28 */ 29 static LIST_HEAD(trace_bprintk_fmt_list); 30 31 /* serialize accesses to trace_bprintk_fmt_list */ 32 static DEFINE_MUTEX(btrace_mutex); 33 34 struct trace_bprintk_fmt { 35 struct list_head list; 36 char fmt[0]; 37 }; 38 39 static inline struct trace_bprintk_fmt *lookup_format(const char *fmt) 40 { 41 struct trace_bprintk_fmt *pos; 42 list_for_each_entry(pos, &trace_bprintk_fmt_list, list) { 43 if (!strcmp(pos->fmt, fmt)) 44 return pos; 45 } 46 return NULL; 47 } 48 49 static 50 void hold_module_trace_bprintk_format(const char **start, const char **end) 51 { 52 const char **iter; 53 54 mutex_lock(&btrace_mutex); 55 for (iter = start; iter < end; iter++) { 56 struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter); 57 if (tb_fmt) { 58 *iter = tb_fmt->fmt; 59 continue; 60 } 61 62 tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt) 63 + strlen(*iter) + 1, GFP_KERNEL); 64 if (tb_fmt) { 65 list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list); 66 strcpy(tb_fmt->fmt, *iter); 67 *iter = tb_fmt->fmt; 68 } else 69 *iter = NULL; 70 } 71 mutex_unlock(&btrace_mutex); 72 } 73 74 static int module_trace_bprintk_format_notify(struct notifier_block *self, 75 unsigned long val, void *data) 76 { 77 struct module *mod = data; 78 if (mod->num_trace_bprintk_fmt) { 79 const char **start = mod->trace_bprintk_fmt_start; 80 const char **end = start + mod->num_trace_bprintk_fmt; 81 82 if (val == MODULE_STATE_COMING) 83 hold_module_trace_bprintk_format(start, end); 84 } 85 return 0; 86 } 87 88 #else /* !CONFIG_MODULES */ 89 __init static int 90 module_trace_bprintk_format_notify(struct notifier_block *self, 91 unsigned long val, void *data) 92 { 93 return 0; 94 } 95 #endif /* CONFIG_MODULES */ 96 97 98 __initdata_or_module static 99 struct notifier_block module_trace_bprintk_format_nb = { 100 .notifier_call = module_trace_bprintk_format_notify, 101 }; 102 103 int __trace_bprintk(unsigned long ip, const char *fmt, ...) 104 { 105 int ret; 106 va_list ap; 107 108 if (unlikely(!fmt)) 109 return 0; 110 111 if (!(trace_flags & TRACE_ITER_PRINTK)) 112 return 0; 113 114 va_start(ap, fmt); 115 ret = trace_vbprintk(ip, fmt, ap); 116 va_end(ap); 117 return ret; 118 } 119 EXPORT_SYMBOL_GPL(__trace_bprintk); 120 121 int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap) 122 { 123 if (unlikely(!fmt)) 124 return 0; 125 126 if (!(trace_flags & TRACE_ITER_PRINTK)) 127 return 0; 128 129 return trace_vbprintk(ip, fmt, ap); 130 } 131 EXPORT_SYMBOL_GPL(__ftrace_vbprintk); 132 133 int __trace_printk(unsigned long ip, const char *fmt, ...) 134 { 135 int ret; 136 va_list ap; 137 138 if (!(trace_flags & TRACE_ITER_PRINTK)) 139 return 0; 140 141 va_start(ap, fmt); 142 ret = trace_vprintk(ip, fmt, ap); 143 va_end(ap); 144 return ret; 145 } 146 EXPORT_SYMBOL_GPL(__trace_printk); 147 148 int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) 149 { 150 if (!(trace_flags & TRACE_ITER_PRINTK)) 151 return 0; 152 153 return trace_vprintk(ip, fmt, ap); 154 } 155 EXPORT_SYMBOL_GPL(__ftrace_vprintk); 156 157 static void * 158 t_start(struct seq_file *m, loff_t *pos) 159 { 160 const char **fmt = __start___trace_bprintk_fmt + *pos; 161 162 if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt) 163 return NULL; 164 return fmt; 165 } 166 167 static void *t_next(struct seq_file *m, void * v, loff_t *pos) 168 { 169 (*pos)++; 170 return t_start(m, pos); 171 } 172 173 static int t_show(struct seq_file *m, void *v) 174 { 175 const char **fmt = v; 176 const char *str = *fmt; 177 int i; 178 179 seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); 180 181 /* 182 * Tabs and new lines need to be converted. 183 */ 184 for (i = 0; str[i]; i++) { 185 switch (str[i]) { 186 case '\n': 187 seq_puts(m, "\\n"); 188 break; 189 case '\t': 190 seq_puts(m, "\\t"); 191 break; 192 case '\\': 193 seq_puts(m, "\\"); 194 break; 195 case '"': 196 seq_puts(m, "\\\""); 197 break; 198 default: 199 seq_putc(m, str[i]); 200 } 201 } 202 seq_puts(m, "\"\n"); 203 204 return 0; 205 } 206 207 static void t_stop(struct seq_file *m, void *p) 208 { 209 } 210 211 static const struct seq_operations show_format_seq_ops = { 212 .start = t_start, 213 .next = t_next, 214 .show = t_show, 215 .stop = t_stop, 216 }; 217 218 static int 219 ftrace_formats_open(struct inode *inode, struct file *file) 220 { 221 return seq_open(file, &show_format_seq_ops); 222 } 223 224 static const struct file_operations ftrace_formats_fops = { 225 .open = ftrace_formats_open, 226 .read = seq_read, 227 .llseek = seq_lseek, 228 .release = seq_release, 229 }; 230 231 static __init int init_trace_printk_function_export(void) 232 { 233 struct dentry *d_tracer; 234 235 d_tracer = tracing_init_dentry(); 236 if (!d_tracer) 237 return 0; 238 239 trace_create_file("printk_formats", 0444, d_tracer, 240 NULL, &ftrace_formats_fops); 241 242 return 0; 243 } 244 245 fs_initcall(init_trace_printk_function_export); 246 247 static __init int init_trace_printk(void) 248 { 249 return register_module_notifier(&module_trace_bprintk_format_nb); 250 } 251 252 early_initcall(init_trace_printk); 253