Branch data Line data Source code
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 Nadia Yvette Chambers
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/fs.h>
17 : :
18 : : #include "trace.h"
19 : :
20 : : /* function tracing enabled */
21 : : static int ftrace_function_enabled;
22 : :
23 : : static struct trace_array *func_trace;
24 : :
25 : : static void tracing_start_function_trace(void);
26 : : static void tracing_stop_function_trace(void);
27 : :
28 : 0 : static int function_trace_init(struct trace_array *tr)
29 : : {
30 : 0 : func_trace = tr;
31 : 0 : tr->trace_buffer.cpu = get_cpu();
32 : 0 : put_cpu();
33 : :
34 : 0 : tracing_start_cmdline_record();
35 : 0 : tracing_start_function_trace();
36 : 0 : return 0;
37 : : }
38 : :
39 : 0 : static void function_trace_reset(struct trace_array *tr)
40 : : {
41 : 0 : tracing_stop_function_trace();
42 : 0 : tracing_stop_cmdline_record();
43 : 0 : }
44 : :
45 : 0 : static void function_trace_start(struct trace_array *tr)
46 : : {
47 : 0 : tracing_reset_online_cpus(&tr->trace_buffer);
48 : 0 : }
49 : :
50 : : /* Our option */
51 : : enum {
52 : : TRACE_FUNC_OPT_STACK = 0x1,
53 : : };
54 : :
55 : : static struct tracer_flags func_flags;
56 : :
57 : : static void
58 : 0 : function_trace_call(unsigned long ip, unsigned long parent_ip,
59 : : struct ftrace_ops *op, struct pt_regs *pt_regs)
60 : : {
61 : 0 : struct trace_array *tr = func_trace;
62 : : struct trace_array_cpu *data;
63 : : unsigned long flags;
64 : : int bit;
65 : : int cpu;
66 : : int pc;
67 : :
68 [ # # ]: 0 : if (unlikely(!ftrace_function_enabled))
69 : 0 : return;
70 : :
71 : : pc = preempt_count();
72 : 0 : preempt_disable_notrace();
73 : :
74 : : bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
75 [ # # ]: 0 : if (bit < 0)
76 : : goto out;
77 : :
78 : 0 : cpu = smp_processor_id();
79 : 0 : data = per_cpu_ptr(tr->trace_buffer.data, cpu);
80 [ # # ]: 0 : if (!atomic_read(&data->disabled)) {
81 : : local_save_flags(flags);
82 : 0 : trace_function(tr, ip, parent_ip, flags, pc);
83 : : }
84 : : trace_clear_recursion(bit);
85 : :
86 : : out:
87 : 0 : preempt_enable_notrace();
88 : : }
89 : :
90 : : static void
91 : 0 : function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
92 : : struct ftrace_ops *op, struct pt_regs *pt_regs)
93 : : {
94 : 0 : struct trace_array *tr = func_trace;
95 : : struct trace_array_cpu *data;
96 : : unsigned long flags;
97 : : long disabled;
98 : : int cpu;
99 : : int pc;
100 : :
101 [ # # ]: 0 : if (unlikely(!ftrace_function_enabled))
102 : 0 : return;
103 : :
104 : : /*
105 : : * Need to use raw, since this must be called before the
106 : : * recursive protection is performed.
107 : : */
108 : : local_irq_save(flags);
109 : 0 : cpu = raw_smp_processor_id();
110 : 0 : data = per_cpu_ptr(tr->trace_buffer.data, cpu);
111 : 0 : disabled = atomic_inc_return(&data->disabled);
112 : :
113 [ # # ]: 0 : if (likely(disabled == 1)) {
114 : : pc = preempt_count();
115 : 0 : trace_function(tr, ip, parent_ip, flags, pc);
116 : : /*
117 : : * skip over 5 funcs:
118 : : * __ftrace_trace_stack,
119 : : * __trace_stack,
120 : : * function_stack_trace_call
121 : : * ftrace_list_func
122 : : * ftrace_call
123 : : */
124 : 0 : __trace_stack(tr, flags, 5, pc);
125 : : }
126 : :
127 : : atomic_dec(&data->disabled);
128 [ # # ]: 0 : local_irq_restore(flags);
129 : : }
130 : :
131 : :
132 : : static struct ftrace_ops trace_ops __read_mostly =
133 : : {
134 : : .func = function_trace_call,
135 : : .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
136 : : };
137 : :
138 : : static struct ftrace_ops trace_stack_ops __read_mostly =
139 : : {
140 : : .func = function_stack_trace_call,
141 : : .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE,
142 : : };
143 : :
144 : : static struct tracer_opt func_opts[] = {
145 : : #ifdef CONFIG_STACKTRACE
146 : : { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) },
147 : : #endif
148 : : { } /* Always set a last empty entry */
149 : : };
150 : :
151 : : static struct tracer_flags func_flags = {
152 : : .val = 0, /* By default: all flags disabled */
153 : : .opts = func_opts
154 : : };
155 : :
156 : 0 : static void tracing_start_function_trace(void)
157 : : {
158 : 0 : ftrace_function_enabled = 0;
159 : :
160 [ # # ]: 0 : if (func_flags.val & TRACE_FUNC_OPT_STACK)
161 : 0 : register_ftrace_function(&trace_stack_ops);
162 : : else
163 : 0 : register_ftrace_function(&trace_ops);
164 : :
165 : 0 : ftrace_function_enabled = 1;
166 : 0 : }
167 : :
168 : 0 : static void tracing_stop_function_trace(void)
169 : : {
170 : 0 : ftrace_function_enabled = 0;
171 : :
172 [ # # ]: 0 : if (func_flags.val & TRACE_FUNC_OPT_STACK)
173 : 0 : unregister_ftrace_function(&trace_stack_ops);
174 : : else
175 : 0 : unregister_ftrace_function(&trace_ops);
176 : 0 : }
177 : :
178 : 0 : static int func_set_flag(u32 old_flags, u32 bit, int set)
179 : : {
180 [ # # ]: 0 : switch (bit) {
181 : : case TRACE_FUNC_OPT_STACK:
182 : : /* do nothing if already set */
183 [ # # ]: 0 : if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
184 : : break;
185 : :
186 [ # # ]: 0 : if (set) {
187 : 0 : unregister_ftrace_function(&trace_ops);
188 : 0 : register_ftrace_function(&trace_stack_ops);
189 : : } else {
190 : 0 : unregister_ftrace_function(&trace_stack_ops);
191 : 0 : register_ftrace_function(&trace_ops);
192 : : }
193 : :
194 : : break;
195 : : default:
196 : : return -EINVAL;
197 : : }
198 : :
199 : : return 0;
200 : : }
201 : :
202 : : static struct tracer function_trace __tracer_data =
203 : : {
204 : : .name = "function",
205 : : .init = function_trace_init,
206 : : .reset = function_trace_reset,
207 : : .start = function_trace_start,
208 : : .wait_pipe = poll_wait_pipe,
209 : : .flags = &func_flags,
210 : : .set_flag = func_set_flag,
211 : : #ifdef CONFIG_FTRACE_SELFTEST
212 : : .selftest = trace_selftest_startup_function,
213 : : #endif
214 : : };
215 : :
216 : : #ifdef CONFIG_DYNAMIC_FTRACE
217 : : static int update_count(void **data)
218 : : {
219 : : unsigned long *count = (long *)data;
220 : :
221 [ # # ][ # # ]: 0 : if (!*count)
[ # # ][ # # ]
[ # # ]
222 : : return 0;
223 : :
224 [ # # ][ # # ]: 0 : if (*count != -1)
[ # # ][ # # ]
[ # # ]
225 : 0 : (*count)--;
226 : :
227 : : return 1;
228 : : }
229 : :
230 : : static void
231 : 0 : ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, void **data)
232 : : {
233 [ # # ]: 0 : if (tracing_is_on())
234 : 0 : return;
235 : :
236 [ # # ]: 0 : if (update_count(data))
237 : 0 : tracing_on();
238 : : }
239 : :
240 : : static void
241 : 0 : ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, void **data)
242 : : {
243 [ # # ]: 0 : if (!tracing_is_on())
244 : 0 : return;
245 : :
246 [ # # ]: 0 : if (update_count(data))
247 : 0 : tracing_off();
248 : : }
249 : :
250 : : static void
251 : 0 : ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
252 : : {
253 [ # # ]: 0 : if (tracing_is_on())
254 : 0 : return;
255 : :
256 : 0 : tracing_on();
257 : : }
258 : :
259 : : static void
260 : 0 : ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
261 : : {
262 [ # # ]: 0 : if (!tracing_is_on())
263 : 0 : return;
264 : :
265 : 0 : tracing_off();
266 : : }
267 : :
268 : : /*
269 : : * Skip 4:
270 : : * ftrace_stacktrace()
271 : : * function_trace_probe_call()
272 : : * ftrace_ops_list_func()
273 : : * ftrace_call()
274 : : */
275 : : #define STACK_SKIP 4
276 : :
277 : : static void
278 : 0 : ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data)
279 : : {
280 : 0 : trace_dump_stack(STACK_SKIP);
281 : 0 : }
282 : :
283 : : static void
284 : 0 : ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
285 : : {
286 [ # # ]: 0 : if (!tracing_is_on())
287 : 0 : return;
288 : :
289 [ # # ]: 0 : if (update_count(data))
290 : 0 : trace_dump_stack(STACK_SKIP);
291 : : }
292 : :
293 : : static void
294 : 0 : ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data)
295 : : {
296 [ # # ]: 0 : if (update_count(data))
297 : 0 : ftrace_dump(DUMP_ALL);
298 : 0 : }
299 : :
300 : : /* Only dump the current CPU buffer. */
301 : : static void
302 : 0 : ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, void **data)
303 : : {
304 [ # # ]: 0 : if (update_count(data))
305 : 0 : ftrace_dump(DUMP_ORIG);
306 : 0 : }
307 : :
308 : : static int
309 : 0 : ftrace_probe_print(const char *name, struct seq_file *m,
310 : : unsigned long ip, void *data)
311 : : {
312 : 0 : long count = (long)data;
313 : :
314 : 0 : seq_printf(m, "%ps:%s", (void *)ip, name);
315 : :
316 [ # # ]: 0 : if (count == -1)
317 : 0 : seq_printf(m, ":unlimited\n");
318 : : else
319 : 0 : seq_printf(m, ":count=%ld\n", count);
320 : :
321 : 0 : return 0;
322 : : }
323 : :
324 : : static int
325 : 0 : ftrace_traceon_print(struct seq_file *m, unsigned long ip,
326 : : struct ftrace_probe_ops *ops, void *data)
327 : : {
328 : 0 : return ftrace_probe_print("traceon", m, ip, data);
329 : : }
330 : :
331 : : static int
332 : 0 : ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
333 : : struct ftrace_probe_ops *ops, void *data)
334 : : {
335 : 0 : return ftrace_probe_print("traceoff", m, ip, data);
336 : : }
337 : :
338 : : static int
339 : 0 : ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
340 : : struct ftrace_probe_ops *ops, void *data)
341 : : {
342 : 0 : return ftrace_probe_print("stacktrace", m, ip, data);
343 : : }
344 : :
345 : : static int
346 : 0 : ftrace_dump_print(struct seq_file *m, unsigned long ip,
347 : : struct ftrace_probe_ops *ops, void *data)
348 : : {
349 : 0 : return ftrace_probe_print("dump", m, ip, data);
350 : : }
351 : :
352 : : static int
353 : 0 : ftrace_cpudump_print(struct seq_file *m, unsigned long ip,
354 : : struct ftrace_probe_ops *ops, void *data)
355 : : {
356 : 0 : return ftrace_probe_print("cpudump", m, ip, data);
357 : : }
358 : :
359 : : static struct ftrace_probe_ops traceon_count_probe_ops = {
360 : : .func = ftrace_traceon_count,
361 : : .print = ftrace_traceon_print,
362 : : };
363 : :
364 : : static struct ftrace_probe_ops traceoff_count_probe_ops = {
365 : : .func = ftrace_traceoff_count,
366 : : .print = ftrace_traceoff_print,
367 : : };
368 : :
369 : : static struct ftrace_probe_ops stacktrace_count_probe_ops = {
370 : : .func = ftrace_stacktrace_count,
371 : : .print = ftrace_stacktrace_print,
372 : : };
373 : :
374 : : static struct ftrace_probe_ops dump_probe_ops = {
375 : : .func = ftrace_dump_probe,
376 : : .print = ftrace_dump_print,
377 : : };
378 : :
379 : : static struct ftrace_probe_ops cpudump_probe_ops = {
380 : : .func = ftrace_cpudump_probe,
381 : : .print = ftrace_cpudump_print,
382 : : };
383 : :
384 : : static struct ftrace_probe_ops traceon_probe_ops = {
385 : : .func = ftrace_traceon,
386 : : .print = ftrace_traceon_print,
387 : : };
388 : :
389 : : static struct ftrace_probe_ops traceoff_probe_ops = {
390 : : .func = ftrace_traceoff,
391 : : .print = ftrace_traceoff_print,
392 : : };
393 : :
394 : : static struct ftrace_probe_ops stacktrace_probe_ops = {
395 : : .func = ftrace_stacktrace,
396 : : .print = ftrace_stacktrace_print,
397 : : };
398 : :
399 : : static int
400 : 0 : ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
401 : : struct ftrace_hash *hash, char *glob,
402 : : char *cmd, char *param, int enable)
403 : : {
404 : 0 : void *count = (void *)-1;
405 : : char *number;
406 : : int ret;
407 : :
408 : : /* hash funcs only work with set_ftrace_filter */
409 [ # # ]: 0 : if (!enable)
410 : : return -EINVAL;
411 : :
412 [ # # ]: 0 : if (glob[0] == '!') {
413 : 0 : unregister_ftrace_function_probe_func(glob+1, ops);
414 : : return 0;
415 : : }
416 : :
417 [ # # ]: 0 : if (!param)
418 : : goto out_reg;
419 : :
420 : 0 : number = strsep(¶m, ":");
421 : :
422 [ # # ]: 0 : if (!strlen(number))
423 : : goto out_reg;
424 : :
425 : : /*
426 : : * We use the callback data field (which is a pointer)
427 : : * as our counter.
428 : : */
429 : : ret = kstrtoul(number, 0, (unsigned long *)&count);
430 [ # # ]: 0 : if (ret)
431 : : return ret;
432 : :
433 : : out_reg:
434 : 0 : ret = register_ftrace_function_probe(glob, ops, count);
435 : :
436 : 0 : return ret < 0 ? ret : 0;
437 : : }
438 : :
439 : : static int
440 : 0 : ftrace_trace_onoff_callback(struct ftrace_hash *hash,
441 : : char *glob, char *cmd, char *param, int enable)
442 : : {
443 : : struct ftrace_probe_ops *ops;
444 : :
445 : : /* we register both traceon and traceoff to this callback */
446 [ # # ]: 0 : if (strcmp(cmd, "traceon") == 0)
447 [ # # ]: 0 : ops = param ? &traceon_count_probe_ops : &traceon_probe_ops;
448 : : else
449 [ # # ]: 0 : ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
450 : :
451 : 0 : return ftrace_trace_probe_callback(ops, hash, glob, cmd,
452 : : param, enable);
453 : : }
454 : :
455 : : static int
456 : 0 : ftrace_stacktrace_callback(struct ftrace_hash *hash,
457 : : char *glob, char *cmd, char *param, int enable)
458 : : {
459 : : struct ftrace_probe_ops *ops;
460 : :
461 [ # # ]: 0 : ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops;
462 : :
463 : 0 : return ftrace_trace_probe_callback(ops, hash, glob, cmd,
464 : : param, enable);
465 : : }
466 : :
467 : : static int
468 : 0 : ftrace_dump_callback(struct ftrace_hash *hash,
469 : : char *glob, char *cmd, char *param, int enable)
470 : : {
471 : : struct ftrace_probe_ops *ops;
472 : :
473 : : ops = &dump_probe_ops;
474 : :
475 : : /* Only dump once. */
476 : 0 : return ftrace_trace_probe_callback(ops, hash, glob, cmd,
477 : : "1", enable);
478 : : }
479 : :
480 : : static int
481 : 0 : ftrace_cpudump_callback(struct ftrace_hash *hash,
482 : : char *glob, char *cmd, char *param, int enable)
483 : : {
484 : : struct ftrace_probe_ops *ops;
485 : :
486 : : ops = &cpudump_probe_ops;
487 : :
488 : : /* Only dump once. */
489 : 0 : return ftrace_trace_probe_callback(ops, hash, glob, cmd,
490 : : "1", enable);
491 : : }
492 : :
493 : : static struct ftrace_func_command ftrace_traceon_cmd = {
494 : : .name = "traceon",
495 : : .func = ftrace_trace_onoff_callback,
496 : : };
497 : :
498 : : static struct ftrace_func_command ftrace_traceoff_cmd = {
499 : : .name = "traceoff",
500 : : .func = ftrace_trace_onoff_callback,
501 : : };
502 : :
503 : : static struct ftrace_func_command ftrace_stacktrace_cmd = {
504 : : .name = "stacktrace",
505 : : .func = ftrace_stacktrace_callback,
506 : : };
507 : :
508 : : static struct ftrace_func_command ftrace_dump_cmd = {
509 : : .name = "dump",
510 : : .func = ftrace_dump_callback,
511 : : };
512 : :
513 : : static struct ftrace_func_command ftrace_cpudump_cmd = {
514 : : .name = "cpudump",
515 : : .func = ftrace_cpudump_callback,
516 : : };
517 : :
518 : 0 : static int __init init_func_cmd_traceon(void)
519 : : {
520 : : int ret;
521 : :
522 : 0 : ret = register_ftrace_command(&ftrace_traceoff_cmd);
523 [ # # ]: 0 : if (ret)
524 : : return ret;
525 : :
526 : 0 : ret = register_ftrace_command(&ftrace_traceon_cmd);
527 [ # # ]: 0 : if (ret)
528 : : goto out_free_traceoff;
529 : :
530 : 0 : ret = register_ftrace_command(&ftrace_stacktrace_cmd);
531 [ # # ]: 0 : if (ret)
532 : : goto out_free_traceon;
533 : :
534 : 0 : ret = register_ftrace_command(&ftrace_dump_cmd);
535 [ # # ]: 0 : if (ret)
536 : : goto out_free_stacktrace;
537 : :
538 : 0 : ret = register_ftrace_command(&ftrace_cpudump_cmd);
539 [ # # ]: 0 : if (ret)
540 : : goto out_free_dump;
541 : :
542 : : return 0;
543 : :
544 : : out_free_dump:
545 : 0 : unregister_ftrace_command(&ftrace_dump_cmd);
546 : : out_free_stacktrace:
547 : 0 : unregister_ftrace_command(&ftrace_stacktrace_cmd);
548 : : out_free_traceon:
549 : 0 : unregister_ftrace_command(&ftrace_traceon_cmd);
550 : : out_free_traceoff:
551 : 0 : unregister_ftrace_command(&ftrace_traceoff_cmd);
552 : :
553 : 0 : return ret;
554 : : }
555 : : #else
556 : : static inline int init_func_cmd_traceon(void)
557 : : {
558 : : return 0;
559 : : }
560 : : #endif /* CONFIG_DYNAMIC_FTRACE */
561 : :
562 : 0 : static __init int init_function_trace(void)
563 : : {
564 : 0 : init_func_cmd_traceon();
565 : 0 : return register_tracer(&function_trace);
566 : : }
567 : : core_initcall(init_function_trace);
|