• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/kernel/trace/
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	char fmt[0];
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
53	mutex_lock(&btrace_mutex);
54	for (iter = start; iter < end; iter++) {
55		struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
56		if (tb_fmt) {
57			*iter = tb_fmt->fmt;
58			continue;
59		}
60
61		tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt)
62				+ strlen(*iter) + 1, GFP_KERNEL);
63		if (tb_fmt) {
64			list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
65			strcpy(tb_fmt->fmt, *iter);
66			*iter = tb_fmt->fmt;
67		} else
68			*iter = NULL;
69	}
70	mutex_unlock(&btrace_mutex);
71}
72
73static int module_trace_bprintk_format_notify(struct notifier_block *self,
74		unsigned long val, void *data)
75{
76	struct module *mod = data;
77	if (mod->num_trace_bprintk_fmt) {
78		const char **start = mod->trace_bprintk_fmt_start;
79		const char **end = start + mod->num_trace_bprintk_fmt;
80
81		if (val == MODULE_STATE_COMING)
82			hold_module_trace_bprintk_format(start, end);
83	}
84	return 0;
85}
86
87#else /* !CONFIG_MODULES */
88__init static int
89module_trace_bprintk_format_notify(struct notifier_block *self,
90		unsigned long val, void *data)
91{
92	return 0;
93}
94#endif /* CONFIG_MODULES */
95
96
97__initdata_or_module static
98struct notifier_block module_trace_bprintk_format_nb = {
99	.notifier_call = module_trace_bprintk_format_notify,
100};
101
102int __trace_bprintk(unsigned long ip, const char *fmt, ...)
103 {
104	int ret;
105	va_list ap;
106
107	if (unlikely(!fmt))
108		return 0;
109
110	if (!(trace_flags & TRACE_ITER_PRINTK))
111		return 0;
112
113	va_start(ap, fmt);
114	ret = trace_vbprintk(ip, fmt, ap);
115	va_end(ap);
116	return ret;
117}
118EXPORT_SYMBOL_GPL(__trace_bprintk);
119
120int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
121 {
122	if (unlikely(!fmt))
123		return 0;
124
125	if (!(trace_flags & TRACE_ITER_PRINTK))
126		return 0;
127
128	return trace_vbprintk(ip, fmt, ap);
129}
130EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
131
132int __trace_printk(unsigned long ip, const char *fmt, ...)
133{
134	int ret;
135	va_list ap;
136
137	if (!(trace_flags & TRACE_ITER_PRINTK))
138		return 0;
139
140	va_start(ap, fmt);
141	ret = trace_vprintk(ip, fmt, ap);
142	va_end(ap);
143	return ret;
144}
145EXPORT_SYMBOL_GPL(__trace_printk);
146
147int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
148{
149	if (!(trace_flags & TRACE_ITER_PRINTK))
150		return 0;
151
152	return trace_vprintk(ip, fmt, ap);
153}
154EXPORT_SYMBOL_GPL(__ftrace_vprintk);
155
156static void *
157t_start(struct seq_file *m, loff_t *pos)
158{
159	const char **fmt = __start___trace_bprintk_fmt + *pos;
160
161	if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt)
162		return NULL;
163	return fmt;
164}
165
166static void *t_next(struct seq_file *m, void * v, loff_t *pos)
167{
168	(*pos)++;
169	return t_start(m, pos);
170}
171
172static int t_show(struct seq_file *m, void *v)
173{
174	const char **fmt = v;
175	const char *str = *fmt;
176	int i;
177
178	seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
179
180	/*
181	 * Tabs and new lines need to be converted.
182	 */
183	for (i = 0; str[i]; i++) {
184		switch (str[i]) {
185		case '\n':
186			seq_puts(m, "\\n");
187			break;
188		case '\t':
189			seq_puts(m, "\\t");
190			break;
191		case '\\':
192			seq_puts(m, "\\");
193			break;
194		case '"':
195			seq_puts(m, "\\\"");
196			break;
197		default:
198			seq_putc(m, str[i]);
199		}
200	}
201	seq_puts(m, "\"\n");
202
203	return 0;
204}
205
206static void t_stop(struct seq_file *m, void *p)
207{
208}
209
210static const struct seq_operations show_format_seq_ops = {
211	.start = t_start,
212	.next = t_next,
213	.show = t_show,
214	.stop = t_stop,
215};
216
217static int
218ftrace_formats_open(struct inode *inode, struct file *file)
219{
220	return seq_open(file, &show_format_seq_ops);
221}
222
223static const struct file_operations ftrace_formats_fops = {
224	.open = ftrace_formats_open,
225	.read = seq_read,
226	.llseek = seq_lseek,
227	.release = seq_release,
228};
229
230static __init int init_trace_printk_function_export(void)
231{
232	struct dentry *d_tracer;
233
234	d_tracer = tracing_init_dentry();
235	if (!d_tracer)
236		return 0;
237
238	trace_create_file("printk_formats", 0444, d_tracer,
239				    NULL, &ftrace_formats_fops);
240
241	return 0;
242}
243
244fs_initcall(init_trace_printk_function_export);
245
246static __init int init_trace_printk(void)
247{
248	return register_module_notifier(&module_trace_bprintk_format_nb);
249}
250
251early_initcall(init_trace_printk);
252