Merge branch 'topic/hda' into for-linus
[linux-2.6] / 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_next(struct seq_file *m, void *v, loff_t *pos)
159 {
160         const char **fmt = m->private;
161         const char **next = fmt;
162
163         (*pos)++;
164
165         if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt)
166                 return NULL;
167
168         next = fmt;
169         m->private = ++next;
170
171         return fmt;
172 }
173
174 static void *t_start(struct seq_file *m, loff_t *pos)
175 {
176         return t_next(m, NULL, pos);
177 }
178
179 static int t_show(struct seq_file *m, void *v)
180 {
181         const char **fmt = v;
182         const char *str = *fmt;
183         int i;
184
185         seq_printf(m, "0x%lx : \"", (unsigned long)fmt);
186
187         /*
188          * Tabs and new lines need to be converted.
189          */
190         for (i = 0; str[i]; i++) {
191                 switch (str[i]) {
192                 case '\n':
193                         seq_puts(m, "\\n");
194                         break;
195                 case '\t':
196                         seq_puts(m, "\\t");
197                         break;
198                 case '\\':
199                         seq_puts(m, "\\");
200                         break;
201                 case '"':
202                         seq_puts(m, "\\\"");
203                         break;
204                 default:
205                         seq_putc(m, str[i]);
206                 }
207         }
208         seq_puts(m, "\"\n");
209
210         return 0;
211 }
212
213 static void t_stop(struct seq_file *m, void *p)
214 {
215 }
216
217 static const struct seq_operations show_format_seq_ops = {
218         .start = t_start,
219         .next = t_next,
220         .show = t_show,
221         .stop = t_stop,
222 };
223
224 static int
225 ftrace_formats_open(struct inode *inode, struct file *file)
226 {
227         int ret;
228
229         ret = seq_open(file, &show_format_seq_ops);
230         if (!ret) {
231                 struct seq_file *m = file->private_data;
232
233                 m->private = __start___trace_bprintk_fmt;
234         }
235         return ret;
236 }
237
238 static const struct file_operations ftrace_formats_fops = {
239         .open = ftrace_formats_open,
240         .read = seq_read,
241         .llseek = seq_lseek,
242         .release = seq_release,
243 };
244
245 static __init int init_trace_printk_function_export(void)
246 {
247         struct dentry *d_tracer;
248         struct dentry *entry;
249
250         d_tracer = tracing_init_dentry();
251         if (!d_tracer)
252                 return 0;
253
254         entry = debugfs_create_file("printk_formats", 0444, d_tracer,
255                                     NULL, &ftrace_formats_fops);
256         if (!entry)
257                 pr_warning("Could not create debugfs "
258                            "'printk_formats' entry\n");
259
260         return 0;
261 }
262
263 fs_initcall(init_trace_printk_function_export);
264
265 static __init int init_trace_printk(void)
266 {
267         return register_module_notifier(&module_trace_bprintk_format_nb);
268 }
269
270 early_initcall(init_trace_printk);