Merge branch 'fix/misc' into for-linus
[pandora-kernel.git] / kernel / trace / trace_printk.c
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);