Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * trace binary printk
4 : : *
5 : : * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com>
6 : : *
7 : : */
8 : : #include <linux/seq_file.h>
9 : : #include <linux/security.h>
10 : : #include <linux/uaccess.h>
11 : : #include <linux/kernel.h>
12 : : #include <linux/ftrace.h>
13 : : #include <linux/string.h>
14 : : #include <linux/module.h>
15 : : #include <linux/mutex.h>
16 : : #include <linux/ctype.h>
17 : : #include <linux/list.h>
18 : : #include <linux/slab.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 : : const char *fmt;
36 : : };
37 : :
38 : 0 : static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
39 : : {
40 : 0 : struct trace_bprintk_fmt *pos;
41 : :
42 [ # # ]: 0 : if (!fmt)
43 : : return ERR_PTR(-EINVAL);
44 : :
45 [ # # ]: 0 : list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
46 [ # # ]: 0 : if (!strcmp(pos->fmt, fmt))
47 : 0 : return pos;
48 : : }
49 : : return NULL;
50 : : }
51 : :
52 : : static
53 : 0 : void hold_module_trace_bprintk_format(const char **start, const char **end)
54 : : {
55 : 0 : const char **iter;
56 : 0 : char *fmt;
57 : :
58 : : /* allocate the trace_printk per cpu buffers */
59 [ # # ]: 0 : if (start != end)
60 : 0 : trace_printk_init_buffers();
61 : :
62 : 0 : mutex_lock(&btrace_mutex);
63 [ # # ]: 0 : for (iter = start; iter < end; iter++) {
64 : 0 : struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
65 [ # # ]: 0 : if (tb_fmt) {
66 [ # # ]: 0 : if (!IS_ERR(tb_fmt))
67 : 0 : *iter = tb_fmt->fmt;
68 : 0 : continue;
69 : : }
70 : :
71 : 0 : fmt = NULL;
72 : 0 : tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
73 [ # # ]: 0 : if (tb_fmt) {
74 [ # # ]: 0 : fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
75 [ # # ]: 0 : if (fmt) {
76 : 0 : list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
77 : 0 : strcpy(fmt, *iter);
78 : 0 : tb_fmt->fmt = fmt;
79 : : } else
80 : 0 : kfree(tb_fmt);
81 : : }
82 : 0 : *iter = fmt;
83 : :
84 : : }
85 : 0 : mutex_unlock(&btrace_mutex);
86 : 0 : }
87 : :
88 : 22 : static int module_trace_bprintk_format_notify(struct notifier_block *self,
89 : : unsigned long val, void *data)
90 : : {
91 : 22 : struct module *mod = data;
92 [ - + ]: 22 : if (mod->num_trace_bprintk_fmt) {
93 : 0 : const char **start = mod->trace_bprintk_fmt_start;
94 : 0 : const char **end = start + mod->num_trace_bprintk_fmt;
95 : :
96 [ # # ]: 0 : if (val == MODULE_STATE_COMING)
97 : 0 : hold_module_trace_bprintk_format(start, end);
98 : : }
99 : 22 : return 0;
100 : : }
101 : :
102 : : /*
103 : : * The debugfs/tracing/printk_formats file maps the addresses with
104 : : * the ASCII formats that are used in the bprintk events in the
105 : : * buffer. For userspace tools to be able to decode the events from
106 : : * the buffer, they need to be able to map the address with the format.
107 : : *
108 : : * The addresses of the bprintk formats are in their own section
109 : : * __trace_printk_fmt. But for modules we copy them into a link list.
110 : : * The code to print the formats and their addresses passes around the
111 : : * address of the fmt string. If the fmt address passed into the seq
112 : : * functions is within the kernel core __trace_printk_fmt section, then
113 : : * it simply uses the next pointer in the list.
114 : : *
115 : : * When the fmt pointer is outside the kernel core __trace_printk_fmt
116 : : * section, then we need to read the link list pointers. The trick is
117 : : * we pass the address of the string to the seq function just like
118 : : * we do for the kernel core formats. To get back the structure that
119 : : * holds the format, we simply use container_of() and then go to the
120 : : * next format in the list.
121 : : */
122 : : static const char **
123 : : find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
124 : : {
125 : : struct trace_bprintk_fmt *mod_fmt;
126 : :
127 : : if (list_empty(&trace_bprintk_fmt_list))
128 : : return NULL;
129 : :
130 : : /*
131 : : * v will point to the address of the fmt record from t_next
132 : : * v will be NULL from t_start.
133 : : * If this is the first pointer or called from start
134 : : * then we need to walk the list.
135 : : */
136 : : if (!v || start_index == *pos) {
137 : : struct trace_bprintk_fmt *p;
138 : :
139 : : /* search the module list */
140 : : list_for_each_entry(p, &trace_bprintk_fmt_list, list) {
141 : : if (start_index == *pos)
142 : : return &p->fmt;
143 : : start_index++;
144 : : }
145 : : /* pos > index */
146 : : return NULL;
147 : : }
148 : :
149 : : /*
150 : : * v points to the address of the fmt field in the mod list
151 : : * structure that holds the module print format.
152 : : */
153 : : mod_fmt = container_of(v, typeof(*mod_fmt), fmt);
154 : : if (mod_fmt->list.next == &trace_bprintk_fmt_list)
155 : : return NULL;
156 : :
157 : : mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list);
158 : :
159 : : return &mod_fmt->fmt;
160 : : }
161 : :
162 : 0 : static void format_mod_start(void)
163 : : {
164 : 0 : mutex_lock(&btrace_mutex);
165 : : }
166 : :
167 : 0 : static void format_mod_stop(void)
168 : : {
169 : 0 : mutex_unlock(&btrace_mutex);
170 : : }
171 : :
172 : : #else /* !CONFIG_MODULES */
173 : : __init static int
174 : : module_trace_bprintk_format_notify(struct notifier_block *self,
175 : : unsigned long val, void *data)
176 : : {
177 : : return 0;
178 : : }
179 : : static inline const char **
180 : : find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
181 : : {
182 : : return NULL;
183 : : }
184 : : static inline void format_mod_start(void) { }
185 : : static inline void format_mod_stop(void) { }
186 : : #endif /* CONFIG_MODULES */
187 : :
188 : : static bool __read_mostly trace_printk_enabled = true;
189 : :
190 : 0 : void trace_printk_control(bool enabled)
191 : : {
192 : 0 : trace_printk_enabled = enabled;
193 : 0 : }
194 : :
195 : : __initdata_or_module static
196 : : struct notifier_block module_trace_bprintk_format_nb = {
197 : : .notifier_call = module_trace_bprintk_format_notify,
198 : : };
199 : :
200 : 0 : int __trace_bprintk(unsigned long ip, const char *fmt, ...)
201 : : {
202 : 0 : int ret;
203 : 0 : va_list ap;
204 : :
205 [ # # ]: 0 : if (unlikely(!fmt))
206 : : return 0;
207 : :
208 [ # # ]: 0 : if (!trace_printk_enabled)
209 : : return 0;
210 : :
211 : 0 : va_start(ap, fmt);
212 : 0 : ret = trace_vbprintk(ip, fmt, ap);
213 : 0 : va_end(ap);
214 : 0 : return ret;
215 : : }
216 : : EXPORT_SYMBOL_GPL(__trace_bprintk);
217 : :
218 : 0 : int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
219 : : {
220 [ # # ]: 0 : if (unlikely(!fmt))
221 : : return 0;
222 : :
223 [ # # ]: 0 : if (!trace_printk_enabled)
224 : : return 0;
225 : :
226 : 0 : return trace_vbprintk(ip, fmt, ap);
227 : : }
228 : : EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
229 : :
230 : 0 : int __trace_printk(unsigned long ip, const char *fmt, ...)
231 : : {
232 : 0 : int ret;
233 : 0 : va_list ap;
234 : :
235 [ # # ]: 0 : if (!trace_printk_enabled)
236 : : return 0;
237 : :
238 : 0 : va_start(ap, fmt);
239 : 0 : ret = trace_vprintk(ip, fmt, ap);
240 : 0 : va_end(ap);
241 : 0 : return ret;
242 : : }
243 : : EXPORT_SYMBOL_GPL(__trace_printk);
244 : :
245 : 0 : int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
246 : : {
247 [ # # ]: 0 : if (!trace_printk_enabled)
248 : : return 0;
249 : :
250 : 0 : return trace_vprintk(ip, fmt, ap);
251 : : }
252 : : EXPORT_SYMBOL_GPL(__ftrace_vprintk);
253 : :
254 : : static const char **find_next(void *v, loff_t *pos)
255 : : {
256 : : const char **fmt = v;
257 : : int start_index;
258 : : int last_index;
259 : :
260 : : start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
261 : :
262 : : if (*pos < start_index)
263 : : return __start___trace_bprintk_fmt + *pos;
264 : :
265 : : /*
266 : : * The __tracepoint_str section is treated the same as the
267 : : * __trace_printk_fmt section. The difference is that the
268 : : * __trace_printk_fmt section should only be used by trace_printk()
269 : : * in a debugging environment, as if anything exists in that section
270 : : * the trace_prink() helper buffers are allocated, which would just
271 : : * waste space in a production environment.
272 : : *
273 : : * The __tracepoint_str sections on the other hand are used by
274 : : * tracepoints which need to map pointers to their strings to
275 : : * the ASCII text for userspace.
276 : : */
277 : : last_index = start_index;
278 : : start_index = __stop___tracepoint_str - __start___tracepoint_str;
279 : :
280 : : if (*pos < last_index + start_index)
281 : : return __start___tracepoint_str + (*pos - last_index);
282 : :
283 : : start_index += last_index;
284 : : return find_next_mod_format(start_index, v, fmt, pos);
285 : : }
286 : :
287 : : static void *
288 : 0 : t_start(struct seq_file *m, loff_t *pos)
289 : : {
290 : 0 : format_mod_start();
291 : 0 : return find_next(NULL, pos);
292 : : }
293 : :
294 : 0 : static void *t_next(struct seq_file *m, void * v, loff_t *pos)
295 : : {
296 : 0 : (*pos)++;
297 : 0 : return find_next(v, pos);
298 : : }
299 : :
300 : 0 : static int t_show(struct seq_file *m, void *v)
301 : : {
302 : 0 : const char **fmt = v;
303 : 0 : const char *str = *fmt;
304 : 0 : int i;
305 : :
306 [ # # ]: 0 : if (!*fmt)
307 : : return 0;
308 : :
309 : 0 : seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
310 : :
311 : : /*
312 : : * Tabs and new lines need to be converted.
313 : : */
314 [ # # ]: 0 : for (i = 0; str[i]; i++) {
315 [ # # # # : 0 : switch (str[i]) {
# ]
316 : 0 : case '\n':
317 : 0 : seq_puts(m, "\\n");
318 : 0 : break;
319 : 0 : case '\t':
320 : 0 : seq_puts(m, "\\t");
321 : 0 : break;
322 : 0 : case '\\':
323 : 0 : seq_putc(m, '\\');
324 : 0 : break;
325 : 0 : case '"':
326 : 0 : seq_puts(m, "\\\"");
327 : 0 : break;
328 : 0 : default:
329 : 0 : seq_putc(m, str[i]);
330 : : }
331 : : }
332 : 0 : seq_puts(m, "\"\n");
333 : :
334 : 0 : return 0;
335 : : }
336 : :
337 : 0 : static void t_stop(struct seq_file *m, void *p)
338 : : {
339 : 0 : format_mod_stop();
340 : 0 : }
341 : :
342 : : static const struct seq_operations show_format_seq_ops = {
343 : : .start = t_start,
344 : : .next = t_next,
345 : : .show = t_show,
346 : : .stop = t_stop,
347 : : };
348 : :
349 : : static int
350 : 0 : ftrace_formats_open(struct inode *inode, struct file *file)
351 : : {
352 : 0 : int ret;
353 : :
354 : 0 : ret = security_locked_down(LOCKDOWN_TRACEFS);
355 [ # # ]: 0 : if (ret)
356 : : return ret;
357 : :
358 : 0 : return seq_open(file, &show_format_seq_ops);
359 : : }
360 : :
361 : : static const struct file_operations ftrace_formats_fops = {
362 : : .open = ftrace_formats_open,
363 : : .read = seq_read,
364 : : .llseek = seq_lseek,
365 : : .release = seq_release,
366 : : };
367 : :
368 : 11 : static __init int init_trace_printk_function_export(void)
369 : : {
370 : 11 : struct dentry *d_tracer;
371 : :
372 : 11 : d_tracer = tracing_init_dentry();
373 [ + - ]: 11 : if (IS_ERR(d_tracer))
374 : : return 0;
375 : :
376 : 11 : trace_create_file("printk_formats", 0444, d_tracer,
377 : : NULL, &ftrace_formats_fops);
378 : :
379 : 11 : return 0;
380 : : }
381 : :
382 : : fs_initcall(init_trace_printk_function_export);
383 : :
384 : 11 : static __init int init_trace_printk(void)
385 : : {
386 : 11 : return register_module_notifier(&module_trace_bprintk_format_nb);
387 : : }
388 : :
389 : : early_initcall(init_trace_printk);
|