aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-03-21 23:36:31 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-04-04 12:18:24 -0400
commit1813dc3776c22ad4b0294a6df8434b9a02c98109 (patch)
treeb768010ffd8986d2e1df11a067aa8c47c7a0ae62 /kernel/trace
parent0588fa30db44fd2d4032b36a061c87478a43fbee (diff)
tracing: Print trace_bprintk() formats for modules too
The file debugfs/tracing/printk_formats maps the addresses to the formats that are used by trace_bprintk() so that userspace tools can read the buffer and be able to decode trace_bprintk events to get the format saved when reading the ring buffer directly. This is because trace_bprintk() does not store the format into the buffer, but just the address of the format, which is hidden in the kernel memory. But currently it only exports trace_bprintk()s from the kernel core and not for modules. The modules need their formats exported as well. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_printk.c103
1 files changed, 97 insertions, 6 deletions
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index b8b268158af0..dff763b7baf1 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -89,6 +89,76 @@ static int module_trace_bprintk_format_notify(struct notifier_block *self,
89 return 0; 89 return 0;
90} 90}
91 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
92#else /* !CONFIG_MODULES */ 162#else /* !CONFIG_MODULES */
93__init static int 163__init static int
94module_trace_bprintk_format_notify(struct notifier_block *self, 164module_trace_bprintk_format_notify(struct notifier_block *self,
@@ -96,6 +166,13 @@ module_trace_bprintk_format_notify(struct notifier_block *self,
96{ 166{
97 return 0; 167 return 0;
98} 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) { }
99#endif /* CONFIG_MODULES */ 176#endif /* CONFIG_MODULES */
100 177
101 178
@@ -158,20 +235,33 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
158} 235}
159EXPORT_SYMBOL_GPL(__ftrace_vprintk); 236EXPORT_SYMBOL_GPL(__ftrace_vprintk);
160 237
238static const char **find_next(void *v, loff_t *pos)
239{
240 const char **fmt = v;
241 int start_index;
242
243 if (!fmt)
244 fmt = __start___trace_bprintk_fmt + *pos;
245
246 start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
247
248 if (*pos < start_index)
249 return fmt;
250
251 return find_next_mod_format(start_index, v, fmt, pos);
252}
253
161static void * 254static void *
162t_start(struct seq_file *m, loff_t *pos) 255t_start(struct seq_file *m, loff_t *pos)
163{ 256{
164 const char **fmt = __start___trace_bprintk_fmt + *pos; 257 format_mod_start();
165 258 return find_next(NULL, pos);
166 if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt)
167 return NULL;
168 return fmt;
169} 259}
170 260
171static void *t_next(struct seq_file *m, void * v, loff_t *pos) 261static void *t_next(struct seq_file *m, void * v, loff_t *pos)
172{ 262{
173 (*pos)++; 263 (*pos)++;
174 return t_start(m, pos); 264 return find_next(v, pos);
175} 265}
176 266
177static int t_show(struct seq_file *m, void *v) 267static int t_show(struct seq_file *m, void *v)
@@ -210,6 +300,7 @@ static int t_show(struct seq_file *m, void *v)
210 300
211static void t_stop(struct seq_file *m, void *p) 301static void t_stop(struct seq_file *m, void *p)
212{ 302{
303 format_mod_stop();
213} 304}
214 305
215static const struct seq_operations show_format_seq_ops = { 306static const struct seq_operations show_format_seq_ops = {