Root/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/mutex.h>
15#include <linux/ctype.h>
16#include <linux/list.h>
17#include <linux/slab.h>
18#include <linux/fs.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 */
28static LIST_HEAD(trace_bprintk_fmt_list);
29
30/* serialize accesses to trace_bprintk_fmt_list */
31static DEFINE_MUTEX(btrace_mutex);
32
33struct trace_bprintk_fmt {
34    struct list_head list;
35    const char *fmt;
36};
37
38static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
39{
40    struct trace_bprintk_fmt *pos;
41    list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
42        if (!strcmp(pos->fmt, fmt))
43            return pos;
44    }
45    return NULL;
46}
47
48static
49void hold_module_trace_bprintk_format(const char **start, const char **end)
50{
51    const char **iter;
52    char *fmt;
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(sizeof(*tb_fmt), GFP_KERNEL);
63        if (tb_fmt)
64            fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
65        if (tb_fmt && fmt) {
66            list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
67            strcpy(fmt, *iter);
68            tb_fmt->fmt = fmt;
69            *iter = tb_fmt->fmt;
70        } else {
71            kfree(tb_fmt);
72            *iter = NULL;
73        }
74    }
75    mutex_unlock(&btrace_mutex);
76}
77
78static int module_trace_bprintk_format_notify(struct notifier_block *self,
79        unsigned long val, void *data)
80{
81    struct module *mod = data;
82    if (mod->num_trace_bprintk_fmt) {
83        const char **start = mod->trace_bprintk_fmt_start;
84        const char **end = start + mod->num_trace_bprintk_fmt;
85
86        if (val == MODULE_STATE_COMING)
87            hold_module_trace_bprintk_format(start, end);
88    }
89    return 0;
90}
91
92/*
93 * The debugfs/tracing/printk_formats file maps the addresses with
94 * the ASCII formats that are used in the bprintk events in the
95 * buffer. For userspace tools to be able to decode the events from
96 * the buffer, they need to be able to map the address with the format.
97 *
98 * The addresses of the bprintk formats are in their own section
99 * __trace_printk_fmt. But for modules we copy them into a link list.
100 * The code to print the formats and their addresses passes around the
101 * address of the fmt string. If the fmt address passed into the seq
102 * functions is within the kernel core __trace_printk_fmt section, then
103 * it simply uses the next pointer in the list.
104 *
105 * When the fmt pointer is outside the kernel core __trace_printk_fmt
106 * section, then we need to read the link list pointers. The trick is
107 * we pass the address of the string to the seq function just like
108 * we do for the kernel core formats. To get back the structure that
109 * holds the format, we simply use containerof() and then go to the
110 * next format in the list.
111 */
112static const char **
113find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
114{
115    struct trace_bprintk_fmt *mod_fmt;
116
117    if (list_empty(&trace_bprintk_fmt_list))
118        return NULL;
119
120    /*
121     * v will point to the address of the fmt record from t_next
122     * v will be NULL from t_start.
123     * If this is the first pointer or called from start
124     * then we need to walk the list.
125     */
126    if (!v || start_index == *pos) {
127        struct trace_bprintk_fmt *p;
128
129        /* search the module list */
130        list_for_each_entry(p, &trace_bprintk_fmt_list, list) {
131            if (start_index == *pos)
132                return &p->fmt;
133            start_index++;
134        }
135        /* pos > index */
136        return NULL;
137    }
138
139    /*
140     * v points to the address of the fmt field in the mod list
141     * structure that holds the module print format.
142     */
143    mod_fmt = container_of(v, typeof(*mod_fmt), fmt);
144    if (mod_fmt->list.next == &trace_bprintk_fmt_list)
145        return NULL;
146
147    mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list);
148
149    return &mod_fmt->fmt;
150}
151
152static void format_mod_start(void)
153{
154    mutex_lock(&btrace_mutex);
155}
156
157static void format_mod_stop(void)
158{
159    mutex_unlock(&btrace_mutex);
160}
161
162#else /* !CONFIG_MODULES */
163__init static int
164module_trace_bprintk_format_notify(struct notifier_block *self,
165        unsigned long val, void *data)
166{
167    return 0;
168}
169static inline const char **
170find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
171{
172    return NULL;
173}
174static inline void format_mod_start(void) { }
175static inline void format_mod_stop(void) { }
176#endif /* CONFIG_MODULES */
177
178
179__initdata_or_module static
180struct notifier_block module_trace_bprintk_format_nb = {
181    .notifier_call = module_trace_bprintk_format_notify,
182};
183
184int __trace_bprintk(unsigned long ip, const char *fmt, ...)
185 {
186    int ret;
187    va_list ap;
188
189    if (unlikely(!fmt))
190        return 0;
191
192    if (!(trace_flags & TRACE_ITER_PRINTK))
193        return 0;
194
195    va_start(ap, fmt);
196    ret = trace_vbprintk(ip, fmt, ap);
197    va_end(ap);
198    return ret;
199}
200EXPORT_SYMBOL_GPL(__trace_bprintk);
201
202int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
203 {
204    if (unlikely(!fmt))
205        return 0;
206
207    if (!(trace_flags & TRACE_ITER_PRINTK))
208        return 0;
209
210    return trace_vbprintk(ip, fmt, ap);
211}
212EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
213
214int __trace_printk(unsigned long ip, const char *fmt, ...)
215{
216    int ret;
217    va_list ap;
218
219    if (!(trace_flags & TRACE_ITER_PRINTK))
220        return 0;
221
222    va_start(ap, fmt);
223    ret = trace_vprintk(ip, fmt, ap);
224    va_end(ap);
225    return ret;
226}
227EXPORT_SYMBOL_GPL(__trace_printk);
228
229int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
230{
231    if (!(trace_flags & TRACE_ITER_PRINTK))
232        return 0;
233
234    return trace_vprintk(ip, fmt, ap);
235}
236EXPORT_SYMBOL_GPL(__ftrace_vprintk);
237
238static const char **find_next(void *v, loff_t *pos)
239{
240    const char **fmt = v;
241    int start_index;
242
243    start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
244
245    if (*pos < start_index)
246        return __start___trace_bprintk_fmt + *pos;
247
248    return find_next_mod_format(start_index, v, fmt, pos);
249}
250
251static void *
252t_start(struct seq_file *m, loff_t *pos)
253{
254    format_mod_start();
255    return find_next(NULL, pos);
256}
257
258static void *t_next(struct seq_file *m, void * v, loff_t *pos)
259{
260    (*pos)++;
261    return find_next(v, pos);
262}
263
264static int t_show(struct seq_file *m, void *v)
265{
266    const char **fmt = v;
267    const char *str = *fmt;
268    int i;
269
270    seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
271
272    /*
273     * Tabs and new lines need to be converted.
274     */
275    for (i = 0; str[i]; i++) {
276        switch (str[i]) {
277        case '\n':
278            seq_puts(m, "\\n");
279            break;
280        case '\t':
281            seq_puts(m, "\\t");
282            break;
283        case '\\':
284            seq_puts(m, "\\");
285            break;
286        case '"':
287            seq_puts(m, "\\\"");
288            break;
289        default:
290            seq_putc(m, str[i]);
291        }
292    }
293    seq_puts(m, "\"\n");
294
295    return 0;
296}
297
298static void t_stop(struct seq_file *m, void *p)
299{
300    format_mod_stop();
301}
302
303static const struct seq_operations show_format_seq_ops = {
304    .start = t_start,
305    .next = t_next,
306    .show = t_show,
307    .stop = t_stop,
308};
309
310static int
311ftrace_formats_open(struct inode *inode, struct file *file)
312{
313    return seq_open(file, &show_format_seq_ops);
314}
315
316static const struct file_operations ftrace_formats_fops = {
317    .open = ftrace_formats_open,
318    .read = seq_read,
319    .llseek = seq_lseek,
320    .release = seq_release,
321};
322
323static __init int init_trace_printk_function_export(void)
324{
325    struct dentry *d_tracer;
326
327    d_tracer = tracing_init_dentry();
328    if (!d_tracer)
329        return 0;
330
331    trace_create_file("printk_formats", 0444, d_tracer,
332                    NULL, &ftrace_formats_fops);
333
334    return 0;
335}
336
337fs_initcall(init_trace_printk_function_export);
338
339static __init int init_trace_printk(void)
340{
341    return register_module_notifier(&module_trace_bprintk_format_nb);
342}
343
344early_initcall(init_trace_printk);
345

Archive Download this file



interactive