xref: /openbmc/linux/kernel/trace/trace_printk.c (revision b627b4ed)
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);
271