]> git.karo-electronics.de Git - karo-tx-linux.git/blob - kernel/trace/trace_functions.c
Merge tag 'for-v3.7' of git://git.infradead.org/battery-2.6
[karo-tx-linux.git] / kernel / trace / trace_functions.c
1 /*
2  * ring buffer based function tracer
3  *
4  * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
5  * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
6  *
7  * Based on code from the latency_tracer, that is:
8  *
9  *  Copyright (C) 2004-2006 Ingo Molnar
10  *  Copyright (C) 2004 William Lee Irwin III
11  */
12 #include <linux/ring_buffer.h>
13 #include <linux/debugfs.h>
14 #include <linux/uaccess.h>
15 #include <linux/ftrace.h>
16 #include <linux/pstore.h>
17 #include <linux/fs.h>
18
19 #include "trace.h"
20
21 /* function tracing enabled */
22 static int                      ftrace_function_enabled;
23
24 static struct trace_array       *func_trace;
25
26 static void tracing_start_function_trace(void);
27 static void tracing_stop_function_trace(void);
28
29 static int function_trace_init(struct trace_array *tr)
30 {
31         func_trace = tr;
32         tr->cpu = get_cpu();
33         put_cpu();
34
35         tracing_start_cmdline_record();
36         tracing_start_function_trace();
37         return 0;
38 }
39
40 static void function_trace_reset(struct trace_array *tr)
41 {
42         tracing_stop_function_trace();
43         tracing_stop_cmdline_record();
44 }
45
46 static void function_trace_start(struct trace_array *tr)
47 {
48         tracing_reset_online_cpus(tr);
49 }
50
51 static void
52 function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip,
53                                  struct ftrace_ops *op, struct pt_regs *pt_regs)
54 {
55         struct trace_array *tr = func_trace;
56         struct trace_array_cpu *data;
57         unsigned long flags;
58         long disabled;
59         int cpu;
60         int pc;
61
62         if (unlikely(!ftrace_function_enabled))
63                 return;
64
65         pc = preempt_count();
66         preempt_disable_notrace();
67         local_save_flags(flags);
68         cpu = raw_smp_processor_id();
69         data = tr->data[cpu];
70         disabled = atomic_inc_return(&data->disabled);
71
72         if (likely(disabled == 1))
73                 trace_function(tr, ip, parent_ip, flags, pc);
74
75         atomic_dec(&data->disabled);
76         preempt_enable_notrace();
77 }
78
79 /* Our two options */
80 enum {
81         TRACE_FUNC_OPT_STACK    = 0x1,
82         TRACE_FUNC_OPT_PSTORE   = 0x2,
83 };
84
85 static struct tracer_flags func_flags;
86
87 static void
88 function_trace_call(unsigned long ip, unsigned long parent_ip,
89                     struct ftrace_ops *op, struct pt_regs *pt_regs)
90
91 {
92         struct trace_array *tr = func_trace;
93         struct trace_array_cpu *data;
94         unsigned long flags;
95         long disabled;
96         int cpu;
97         int pc;
98
99         if (unlikely(!ftrace_function_enabled))
100                 return;
101
102         /*
103          * Need to use raw, since this must be called before the
104          * recursive protection is performed.
105          */
106         local_irq_save(flags);
107         cpu = raw_smp_processor_id();
108         data = tr->data[cpu];
109         disabled = atomic_inc_return(&data->disabled);
110
111         if (likely(disabled == 1)) {
112                 /*
113                  * So far tracing doesn't support multiple buffers, so
114                  * we make an explicit call for now.
115                  */
116                 if (unlikely(func_flags.val & TRACE_FUNC_OPT_PSTORE))
117                         pstore_ftrace_call(ip, parent_ip);
118                 pc = preempt_count();
119                 trace_function(tr, ip, parent_ip, flags, pc);
120         }
121
122         atomic_dec(&data->disabled);
123         local_irq_restore(flags);
124 }
125
126 static void
127 function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
128                           struct ftrace_ops *op, struct pt_regs *pt_regs)
129 {
130         struct trace_array *tr = func_trace;
131         struct trace_array_cpu *data;
132         unsigned long flags;
133         long disabled;
134         int cpu;
135         int pc;
136
137         if (unlikely(!ftrace_function_enabled))
138                 return;
139
140         /*
141          * Need to use raw, since this must be called before the
142          * recursive protection is performed.
143          */
144         local_irq_save(flags);
145         cpu = raw_smp_processor_id();
146         data = tr->data[cpu];
147         disabled = atomic_inc_return(&data->disabled);
148
149         if (likely(disabled == 1)) {
150                 pc = preempt_count();
151                 trace_function(tr, ip, parent_ip, flags, pc);
152                 /*
153                  * skip over 5 funcs:
154                  *    __ftrace_trace_stack,
155                  *    __trace_stack,
156                  *    function_stack_trace_call
157                  *    ftrace_list_func
158                  *    ftrace_call
159                  */
160                 __trace_stack(tr, flags, 5, pc);
161         }
162
163         atomic_dec(&data->disabled);
164         local_irq_restore(flags);
165 }
166
167
168 static struct ftrace_ops trace_ops __read_mostly =
169 {
170         .func = function_trace_call,
171         .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
172 };
173
174 static struct ftrace_ops trace_stack_ops __read_mostly =
175 {
176         .func = function_stack_trace_call,
177         .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
178 };
179
180 static struct tracer_opt func_opts[] = {
181 #ifdef CONFIG_STACKTRACE
182         { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) },
183 #endif
184 #ifdef CONFIG_PSTORE_FTRACE
185         { TRACER_OPT(func_pstore, TRACE_FUNC_OPT_PSTORE) },
186 #endif
187         { } /* Always set a last empty entry */
188 };
189
190 static struct tracer_flags func_flags = {
191         .val = 0, /* By default: all flags disabled */
192         .opts = func_opts
193 };
194
195 static void tracing_start_function_trace(void)
196 {
197         ftrace_function_enabled = 0;
198
199         if (trace_flags & TRACE_ITER_PREEMPTONLY)
200                 trace_ops.func = function_trace_call_preempt_only;
201         else
202                 trace_ops.func = function_trace_call;
203
204         if (func_flags.val & TRACE_FUNC_OPT_STACK)
205                 register_ftrace_function(&trace_stack_ops);
206         else
207                 register_ftrace_function(&trace_ops);
208
209         ftrace_function_enabled = 1;
210 }
211
212 static void tracing_stop_function_trace(void)
213 {
214         ftrace_function_enabled = 0;
215
216         if (func_flags.val & TRACE_FUNC_OPT_STACK)
217                 unregister_ftrace_function(&trace_stack_ops);
218         else
219                 unregister_ftrace_function(&trace_ops);
220 }
221
222 static int func_set_flag(u32 old_flags, u32 bit, int set)
223 {
224         switch (bit) {
225         case TRACE_FUNC_OPT_STACK:
226                 /* do nothing if already set */
227                 if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
228                         break;
229
230                 if (set) {
231                         unregister_ftrace_function(&trace_ops);
232                         register_ftrace_function(&trace_stack_ops);
233                 } else {
234                         unregister_ftrace_function(&trace_stack_ops);
235                         register_ftrace_function(&trace_ops);
236                 }
237
238                 break;
239         case TRACE_FUNC_OPT_PSTORE:
240                 break;
241         default:
242                 return -EINVAL;
243         }
244
245         return 0;
246 }
247
248 static struct tracer function_trace __read_mostly =
249 {
250         .name           = "function",
251         .init           = function_trace_init,
252         .reset          = function_trace_reset,
253         .start          = function_trace_start,
254         .wait_pipe      = poll_wait_pipe,
255         .flags          = &func_flags,
256         .set_flag       = func_set_flag,
257 #ifdef CONFIG_FTRACE_SELFTEST
258         .selftest       = trace_selftest_startup_function,
259 #endif
260 };
261
262 #ifdef CONFIG_DYNAMIC_FTRACE
263 static void
264 ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
265 {
266         long *count = (long *)data;
267
268         if (tracing_is_on())
269                 return;
270
271         if (!*count)
272                 return;
273
274         if (*count != -1)
275                 (*count)--;
276
277         tracing_on();
278 }
279
280 static void
281 ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
282 {
283         long *count = (long *)data;
284
285         if (!tracing_is_on())
286                 return;
287
288         if (!*count)
289                 return;
290
291         if (*count != -1)
292                 (*count)--;
293
294         tracing_off();
295 }
296
297 static int
298 ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
299                          struct ftrace_probe_ops *ops, void *data);
300
301 static struct ftrace_probe_ops traceon_probe_ops = {
302         .func                   = ftrace_traceon,
303         .print                  = ftrace_trace_onoff_print,
304 };
305
306 static struct ftrace_probe_ops traceoff_probe_ops = {
307         .func                   = ftrace_traceoff,
308         .print                  = ftrace_trace_onoff_print,
309 };
310
311 static int
312 ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
313                          struct ftrace_probe_ops *ops, void *data)
314 {
315         long count = (long)data;
316
317         seq_printf(m, "%ps:", (void *)ip);
318
319         if (ops == &traceon_probe_ops)
320                 seq_printf(m, "traceon");
321         else
322                 seq_printf(m, "traceoff");
323
324         if (count == -1)
325                 seq_printf(m, ":unlimited\n");
326         else
327                 seq_printf(m, ":count=%ld\n", count);
328
329         return 0;
330 }
331
332 static int
333 ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
334 {
335         struct ftrace_probe_ops *ops;
336
337         /* we register both traceon and traceoff to this callback */
338         if (strcmp(cmd, "traceon") == 0)
339                 ops = &traceon_probe_ops;
340         else
341                 ops = &traceoff_probe_ops;
342
343         unregister_ftrace_function_probe_func(glob, ops);
344
345         return 0;
346 }
347
348 static int
349 ftrace_trace_onoff_callback(struct ftrace_hash *hash,
350                             char *glob, char *cmd, char *param, int enable)
351 {
352         struct ftrace_probe_ops *ops;
353         void *count = (void *)-1;
354         char *number;
355         int ret;
356
357         /* hash funcs only work with set_ftrace_filter */
358         if (!enable)
359                 return -EINVAL;
360
361         if (glob[0] == '!')
362                 return ftrace_trace_onoff_unreg(glob+1, cmd, param);
363
364         /* we register both traceon and traceoff to this callback */
365         if (strcmp(cmd, "traceon") == 0)
366                 ops = &traceon_probe_ops;
367         else
368                 ops = &traceoff_probe_ops;
369
370         if (!param)
371                 goto out_reg;
372
373         number = strsep(&param, ":");
374
375         if (!strlen(number))
376                 goto out_reg;
377
378         /*
379          * We use the callback data field (which is a pointer)
380          * as our counter.
381          */
382         ret = strict_strtoul(number, 0, (unsigned long *)&count);
383         if (ret)
384                 return ret;
385
386  out_reg:
387         ret = register_ftrace_function_probe(glob, ops, count);
388
389         return ret < 0 ? ret : 0;
390 }
391
392 static struct ftrace_func_command ftrace_traceon_cmd = {
393         .name                   = "traceon",
394         .func                   = ftrace_trace_onoff_callback,
395 };
396
397 static struct ftrace_func_command ftrace_traceoff_cmd = {
398         .name                   = "traceoff",
399         .func                   = ftrace_trace_onoff_callback,
400 };
401
402 static int __init init_func_cmd_traceon(void)
403 {
404         int ret;
405
406         ret = register_ftrace_command(&ftrace_traceoff_cmd);
407         if (ret)
408                 return ret;
409
410         ret = register_ftrace_command(&ftrace_traceon_cmd);
411         if (ret)
412                 unregister_ftrace_command(&ftrace_traceoff_cmd);
413         return ret;
414 }
415 #else
416 static inline int init_func_cmd_traceon(void)
417 {
418         return 0;
419 }
420 #endif /* CONFIG_DYNAMIC_FTRACE */
421
422 static __init int init_function_trace(void)
423 {
424         init_func_cmd_traceon();
425         return register_tracer(&function_trace);
426 }
427 device_initcall(init_function_trace);
428