blob: 93e20ed642e535e1bf9426d4413d8d7a9ff62e55 [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * ring buffer based function tracer
4 *
5 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
6 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
7 *
8 * Based on code from the latency_tracer, that is:
9 *
10 * Copyright (C) 2004-2006 Ingo Molnar
11 * Copyright (C) 2004 Nadia Yvette Chambers
12 */
13#include <linux/ring_buffer.h>
14#include <linux/debugfs.h>
15#include <linux/uaccess.h>
16#include <linux/ftrace.h>
17#include <linux/slab.h>
18#include <linux/fs.h>
19
20#include "trace.h"
21
22static void tracing_start_function_trace(struct trace_array *tr);
23static void tracing_stop_function_trace(struct trace_array *tr);
24static void
25function_trace_call(unsigned long ip, unsigned long parent_ip,
26 struct ftrace_ops *op, struct pt_regs *pt_regs);
27static void
28function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
29 struct ftrace_ops *op, struct pt_regs *pt_regs);
30static struct tracer_flags func_flags;
31
32/* Our option */
33enum {
34 TRACE_FUNC_OPT_STACK = 0x1,
35};
36
Olivier Deprez157378f2022-04-04 15:47:50 +020037int ftrace_allocate_ftrace_ops(struct trace_array *tr)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000038{
39 struct ftrace_ops *ops;
40
Olivier Deprez157378f2022-04-04 15:47:50 +020041 /* The top level array uses the "global_ops" */
42 if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
43 return 0;
44
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000045 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
46 if (!ops)
47 return -ENOMEM;
48
Olivier Deprez157378f2022-04-04 15:47:50 +020049 /* Currently only the non stack version is supported */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000050 ops->func = function_trace_call;
51 ops->flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_PID;
52
53 tr->ops = ops;
54 ops->private = tr;
Olivier Deprez157378f2022-04-04 15:47:50 +020055
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000056 return 0;
57}
58
Olivier Deprez157378f2022-04-04 15:47:50 +020059void ftrace_free_ftrace_ops(struct trace_array *tr)
60{
61 kfree(tr->ops);
62 tr->ops = NULL;
63}
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000064
65int ftrace_create_function_files(struct trace_array *tr,
66 struct dentry *parent)
67{
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000068 /*
69 * The top level array uses the "global_ops", and the files are
70 * created on boot up.
71 */
72 if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
73 return 0;
74
Olivier Deprez157378f2022-04-04 15:47:50 +020075 if (!tr->ops)
76 return -EINVAL;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000077
78 ftrace_create_filter_files(tr->ops, parent);
79
80 return 0;
81}
82
83void ftrace_destroy_function_files(struct trace_array *tr)
84{
85 ftrace_destroy_filter_files(tr->ops);
Olivier Deprez157378f2022-04-04 15:47:50 +020086 ftrace_free_ftrace_ops(tr);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000087}
88
89static int function_trace_init(struct trace_array *tr)
90{
91 ftrace_func_t func;
92
93 /*
94 * Instance trace_arrays get their ops allocated
95 * at instance creation. Unless it failed
96 * the allocation.
97 */
98 if (!tr->ops)
99 return -ENOMEM;
100
101 /* Currently only the global instance can do stack tracing */
102 if (tr->flags & TRACE_ARRAY_FL_GLOBAL &&
103 func_flags.val & TRACE_FUNC_OPT_STACK)
104 func = function_stack_trace_call;
105 else
106 func = function_trace_call;
107
108 ftrace_init_array_ops(tr, func);
109
Olivier Deprez157378f2022-04-04 15:47:50 +0200110 tr->array_buffer.cpu = get_cpu();
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000111 put_cpu();
112
113 tracing_start_cmdline_record();
114 tracing_start_function_trace(tr);
115 return 0;
116}
117
118static void function_trace_reset(struct trace_array *tr)
119{
120 tracing_stop_function_trace(tr);
121 tracing_stop_cmdline_record();
122 ftrace_reset_array_ops(tr);
123}
124
125static void function_trace_start(struct trace_array *tr)
126{
Olivier Deprez157378f2022-04-04 15:47:50 +0200127 tracing_reset_online_cpus(&tr->array_buffer);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000128}
129
130static void
131function_trace_call(unsigned long ip, unsigned long parent_ip,
132 struct ftrace_ops *op, struct pt_regs *pt_regs)
133{
134 struct trace_array *tr = op->private;
135 struct trace_array_cpu *data;
136 unsigned long flags;
137 int bit;
138 int cpu;
139 int pc;
140
141 if (unlikely(!tr->function_enabled))
142 return;
143
144 pc = preempt_count();
145 preempt_disable_notrace();
146
Olivier Deprez157378f2022-04-04 15:47:50 +0200147 bit = trace_test_and_set_recursion(TRACE_FTRACE_START);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000148 if (bit < 0)
149 goto out;
150
151 cpu = smp_processor_id();
Olivier Deprez157378f2022-04-04 15:47:50 +0200152 data = per_cpu_ptr(tr->array_buffer.data, cpu);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000153 if (!atomic_read(&data->disabled)) {
154 local_save_flags(flags);
155 trace_function(tr, ip, parent_ip, flags, pc);
156 }
157 trace_clear_recursion(bit);
158
159 out:
160 preempt_enable_notrace();
161}
162
163#ifdef CONFIG_UNWINDER_ORC
164/*
165 * Skip 2:
166 *
167 * function_stack_trace_call()
168 * ftrace_call()
169 */
170#define STACK_SKIP 2
171#else
172/*
173 * Skip 3:
174 * __trace_stack()
175 * function_stack_trace_call()
176 * ftrace_call()
177 */
178#define STACK_SKIP 3
179#endif
180
181static void
182function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
183 struct ftrace_ops *op, struct pt_regs *pt_regs)
184{
185 struct trace_array *tr = op->private;
186 struct trace_array_cpu *data;
187 unsigned long flags;
188 long disabled;
189 int cpu;
190 int pc;
191
192 if (unlikely(!tr->function_enabled))
193 return;
194
195 /*
196 * Need to use raw, since this must be called before the
197 * recursive protection is performed.
198 */
199 local_irq_save(flags);
200 cpu = raw_smp_processor_id();
Olivier Deprez157378f2022-04-04 15:47:50 +0200201 data = per_cpu_ptr(tr->array_buffer.data, cpu);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000202 disabled = atomic_inc_return(&data->disabled);
203
204 if (likely(disabled == 1)) {
205 pc = preempt_count();
206 trace_function(tr, ip, parent_ip, flags, pc);
207 __trace_stack(tr, flags, STACK_SKIP, pc);
208 }
209
210 atomic_dec(&data->disabled);
211 local_irq_restore(flags);
212}
213
214static struct tracer_opt func_opts[] = {
215#ifdef CONFIG_STACKTRACE
216 { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) },
217#endif
218 { } /* Always set a last empty entry */
219};
220
221static struct tracer_flags func_flags = {
222 .val = 0, /* By default: all flags disabled */
223 .opts = func_opts
224};
225
226static void tracing_start_function_trace(struct trace_array *tr)
227{
228 tr->function_enabled = 0;
229 register_ftrace_function(tr->ops);
230 tr->function_enabled = 1;
231}
232
233static void tracing_stop_function_trace(struct trace_array *tr)
234{
235 tr->function_enabled = 0;
236 unregister_ftrace_function(tr->ops);
237}
238
239static struct tracer function_trace;
240
241static int
242func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
243{
244 switch (bit) {
245 case TRACE_FUNC_OPT_STACK:
246 /* do nothing if already set */
247 if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
248 break;
249
250 /* We can change this flag when not running. */
251 if (tr->current_trace != &function_trace)
252 break;
253
254 unregister_ftrace_function(tr->ops);
255
256 if (set) {
257 tr->ops->func = function_stack_trace_call;
258 register_ftrace_function(tr->ops);
259 } else {
260 tr->ops->func = function_trace_call;
261 register_ftrace_function(tr->ops);
262 }
263
264 break;
265 default:
266 return -EINVAL;
267 }
268
269 return 0;
270}
271
272static struct tracer function_trace __tracer_data =
273{
274 .name = "function",
275 .init = function_trace_init,
276 .reset = function_trace_reset,
277 .start = function_trace_start,
278 .flags = &func_flags,
279 .set_flag = func_set_flag,
280 .allow_instances = true,
281#ifdef CONFIG_FTRACE_SELFTEST
282 .selftest = trace_selftest_startup_function,
283#endif
284};
285
286#ifdef CONFIG_DYNAMIC_FTRACE
287static void update_traceon_count(struct ftrace_probe_ops *ops,
288 unsigned long ip,
289 struct trace_array *tr, bool on,
290 void *data)
291{
292 struct ftrace_func_mapper *mapper = data;
293 long *count;
294 long old_count;
295
296 /*
297 * Tracing gets disabled (or enabled) once per count.
298 * This function can be called at the same time on multiple CPUs.
299 * It is fine if both disable (or enable) tracing, as disabling
300 * (or enabling) the second time doesn't do anything as the
301 * state of the tracer is already disabled (or enabled).
302 * What needs to be synchronized in this case is that the count
303 * only gets decremented once, even if the tracer is disabled
304 * (or enabled) twice, as the second one is really a nop.
305 *
306 * The memory barriers guarantee that we only decrement the
307 * counter once. First the count is read to a local variable
308 * and a read barrier is used to make sure that it is loaded
309 * before checking if the tracer is in the state we want.
310 * If the tracer is not in the state we want, then the count
311 * is guaranteed to be the old count.
312 *
313 * Next the tracer is set to the state we want (disabled or enabled)
314 * then a write memory barrier is used to make sure that
315 * the new state is visible before changing the counter by
316 * one minus the old counter. This guarantees that another CPU
317 * executing this code will see the new state before seeing
318 * the new counter value, and would not do anything if the new
319 * counter is seen.
320 *
321 * Note, there is no synchronization between this and a user
322 * setting the tracing_on file. But we currently don't care
323 * about that.
324 */
325 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
326 old_count = *count;
327
328 if (old_count <= 0)
329 return;
330
331 /* Make sure we see count before checking tracing state */
332 smp_rmb();
333
334 if (on == !!tracer_tracing_is_on(tr))
335 return;
336
337 if (on)
338 tracer_tracing_on(tr);
339 else
340 tracer_tracing_off(tr);
341
342 /* Make sure tracing state is visible before updating count */
343 smp_wmb();
344
345 *count = old_count - 1;
346}
347
348static void
349ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
350 struct trace_array *tr, struct ftrace_probe_ops *ops,
351 void *data)
352{
353 update_traceon_count(ops, ip, tr, 1, data);
354}
355
356static void
357ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip,
358 struct trace_array *tr, struct ftrace_probe_ops *ops,
359 void *data)
360{
361 update_traceon_count(ops, ip, tr, 0, data);
362}
363
364static void
365ftrace_traceon(unsigned long ip, unsigned long parent_ip,
366 struct trace_array *tr, struct ftrace_probe_ops *ops,
367 void *data)
368{
369 if (tracer_tracing_is_on(tr))
370 return;
371
372 tracer_tracing_on(tr);
373}
374
375static void
376ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
377 struct trace_array *tr, struct ftrace_probe_ops *ops,
378 void *data)
379{
380 if (!tracer_tracing_is_on(tr))
381 return;
382
383 tracer_tracing_off(tr);
384}
385
386#ifdef CONFIG_UNWINDER_ORC
387/*
388 * Skip 3:
389 *
390 * function_trace_probe_call()
391 * ftrace_ops_assist_func()
392 * ftrace_call()
393 */
394#define FTRACE_STACK_SKIP 3
395#else
396/*
397 * Skip 5:
398 *
399 * __trace_stack()
400 * ftrace_stacktrace()
401 * function_trace_probe_call()
402 * ftrace_ops_assist_func()
403 * ftrace_call()
404 */
405#define FTRACE_STACK_SKIP 5
406#endif
407
408static __always_inline void trace_stack(struct trace_array *tr)
409{
410 unsigned long flags;
411 int pc;
412
413 local_save_flags(flags);
414 pc = preempt_count();
415
416 __trace_stack(tr, flags, FTRACE_STACK_SKIP, pc);
417}
418
419static void
420ftrace_stacktrace(unsigned long ip, unsigned long parent_ip,
421 struct trace_array *tr, struct ftrace_probe_ops *ops,
422 void *data)
423{
424 trace_stack(tr);
425}
426
427static void
428ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
429 struct trace_array *tr, struct ftrace_probe_ops *ops,
430 void *data)
431{
432 struct ftrace_func_mapper *mapper = data;
433 long *count;
434 long old_count;
435 long new_count;
436
437 if (!tracing_is_on())
438 return;
439
440 /* unlimited? */
441 if (!mapper) {
442 trace_stack(tr);
443 return;
444 }
445
446 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
447
448 /*
449 * Stack traces should only execute the number of times the
450 * user specified in the counter.
451 */
452 do {
453 old_count = *count;
454
455 if (!old_count)
456 return;
457
458 new_count = old_count - 1;
459 new_count = cmpxchg(count, old_count, new_count);
460 if (new_count == old_count)
461 trace_stack(tr);
462
463 if (!tracing_is_on())
464 return;
465
466 } while (new_count != old_count);
467}
468
469static int update_count(struct ftrace_probe_ops *ops, unsigned long ip,
470 void *data)
471{
472 struct ftrace_func_mapper *mapper = data;
473 long *count = NULL;
474
475 if (mapper)
476 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
477
478 if (count) {
479 if (*count <= 0)
480 return 0;
481 (*count)--;
482 }
483
484 return 1;
485}
486
487static void
488ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
489 struct trace_array *tr, struct ftrace_probe_ops *ops,
490 void *data)
491{
492 if (update_count(ops, ip, data))
493 ftrace_dump(DUMP_ALL);
494}
495
496/* Only dump the current CPU buffer. */
497static void
498ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip,
499 struct trace_array *tr, struct ftrace_probe_ops *ops,
500 void *data)
501{
502 if (update_count(ops, ip, data))
503 ftrace_dump(DUMP_ORIG);
504}
505
506static int
507ftrace_probe_print(const char *name, struct seq_file *m,
508 unsigned long ip, struct ftrace_probe_ops *ops,
509 void *data)
510{
511 struct ftrace_func_mapper *mapper = data;
512 long *count = NULL;
513
514 seq_printf(m, "%ps:%s", (void *)ip, name);
515
516 if (mapper)
517 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
518
519 if (count)
520 seq_printf(m, ":count=%ld\n", *count);
521 else
522 seq_puts(m, ":unlimited\n");
523
524 return 0;
525}
526
527static int
528ftrace_traceon_print(struct seq_file *m, unsigned long ip,
529 struct ftrace_probe_ops *ops,
530 void *data)
531{
532 return ftrace_probe_print("traceon", m, ip, ops, data);
533}
534
535static int
536ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
537 struct ftrace_probe_ops *ops, void *data)
538{
539 return ftrace_probe_print("traceoff", m, ip, ops, data);
540}
541
542static int
543ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
544 struct ftrace_probe_ops *ops, void *data)
545{
546 return ftrace_probe_print("stacktrace", m, ip, ops, data);
547}
548
549static int
550ftrace_dump_print(struct seq_file *m, unsigned long ip,
551 struct ftrace_probe_ops *ops, void *data)
552{
553 return ftrace_probe_print("dump", m, ip, ops, data);
554}
555
556static int
557ftrace_cpudump_print(struct seq_file *m, unsigned long ip,
558 struct ftrace_probe_ops *ops, void *data)
559{
560 return ftrace_probe_print("cpudump", m, ip, ops, data);
561}
562
563
564static int
565ftrace_count_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
566 unsigned long ip, void *init_data, void **data)
567{
568 struct ftrace_func_mapper *mapper = *data;
569
570 if (!mapper) {
571 mapper = allocate_ftrace_func_mapper();
572 if (!mapper)
573 return -ENOMEM;
574 *data = mapper;
575 }
576
577 return ftrace_func_mapper_add_ip(mapper, ip, init_data);
578}
579
580static void
581ftrace_count_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
582 unsigned long ip, void *data)
583{
584 struct ftrace_func_mapper *mapper = data;
585
586 if (!ip) {
587 free_ftrace_func_mapper(mapper, NULL);
588 return;
589 }
590
591 ftrace_func_mapper_remove_ip(mapper, ip);
592}
593
594static struct ftrace_probe_ops traceon_count_probe_ops = {
595 .func = ftrace_traceon_count,
596 .print = ftrace_traceon_print,
597 .init = ftrace_count_init,
598 .free = ftrace_count_free,
599};
600
601static struct ftrace_probe_ops traceoff_count_probe_ops = {
602 .func = ftrace_traceoff_count,
603 .print = ftrace_traceoff_print,
604 .init = ftrace_count_init,
605 .free = ftrace_count_free,
606};
607
608static struct ftrace_probe_ops stacktrace_count_probe_ops = {
609 .func = ftrace_stacktrace_count,
610 .print = ftrace_stacktrace_print,
611 .init = ftrace_count_init,
612 .free = ftrace_count_free,
613};
614
615static struct ftrace_probe_ops dump_probe_ops = {
616 .func = ftrace_dump_probe,
617 .print = ftrace_dump_print,
618 .init = ftrace_count_init,
619 .free = ftrace_count_free,
620};
621
622static struct ftrace_probe_ops cpudump_probe_ops = {
623 .func = ftrace_cpudump_probe,
624 .print = ftrace_cpudump_print,
625};
626
627static struct ftrace_probe_ops traceon_probe_ops = {
628 .func = ftrace_traceon,
629 .print = ftrace_traceon_print,
630};
631
632static struct ftrace_probe_ops traceoff_probe_ops = {
633 .func = ftrace_traceoff,
634 .print = ftrace_traceoff_print,
635};
636
637static struct ftrace_probe_ops stacktrace_probe_ops = {
638 .func = ftrace_stacktrace,
639 .print = ftrace_stacktrace_print,
640};
641
642static int
643ftrace_trace_probe_callback(struct trace_array *tr,
644 struct ftrace_probe_ops *ops,
645 struct ftrace_hash *hash, char *glob,
646 char *cmd, char *param, int enable)
647{
648 void *count = (void *)-1;
649 char *number;
650 int ret;
651
652 /* hash funcs only work with set_ftrace_filter */
653 if (!enable)
654 return -EINVAL;
655
656 if (glob[0] == '!')
657 return unregister_ftrace_function_probe_func(glob+1, tr, ops);
658
659 if (!param)
660 goto out_reg;
661
662 number = strsep(&param, ":");
663
664 if (!strlen(number))
665 goto out_reg;
666
667 /*
668 * We use the callback data field (which is a pointer)
669 * as our counter.
670 */
671 ret = kstrtoul(number, 0, (unsigned long *)&count);
672 if (ret)
673 return ret;
674
675 out_reg:
676 ret = register_ftrace_function_probe(glob, tr, ops, count);
677
678 return ret < 0 ? ret : 0;
679}
680
681static int
682ftrace_trace_onoff_callback(struct trace_array *tr, struct ftrace_hash *hash,
683 char *glob, char *cmd, char *param, int enable)
684{
685 struct ftrace_probe_ops *ops;
686
687 if (!tr)
688 return -ENODEV;
689
690 /* we register both traceon and traceoff to this callback */
691 if (strcmp(cmd, "traceon") == 0)
692 ops = param ? &traceon_count_probe_ops : &traceon_probe_ops;
693 else
694 ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
695
696 return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
697 param, enable);
698}
699
700static int
701ftrace_stacktrace_callback(struct trace_array *tr, struct ftrace_hash *hash,
702 char *glob, char *cmd, char *param, int enable)
703{
704 struct ftrace_probe_ops *ops;
705
706 if (!tr)
707 return -ENODEV;
708
709 ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops;
710
711 return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
712 param, enable);
713}
714
715static int
716ftrace_dump_callback(struct trace_array *tr, struct ftrace_hash *hash,
717 char *glob, char *cmd, char *param, int enable)
718{
719 struct ftrace_probe_ops *ops;
720
721 if (!tr)
722 return -ENODEV;
723
724 ops = &dump_probe_ops;
725
726 /* Only dump once. */
727 return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
728 "1", enable);
729}
730
731static int
732ftrace_cpudump_callback(struct trace_array *tr, struct ftrace_hash *hash,
733 char *glob, char *cmd, char *param, int enable)
734{
735 struct ftrace_probe_ops *ops;
736
737 if (!tr)
738 return -ENODEV;
739
740 ops = &cpudump_probe_ops;
741
742 /* Only dump once. */
743 return ftrace_trace_probe_callback(tr, ops, hash, glob, cmd,
744 "1", enable);
745}
746
747static struct ftrace_func_command ftrace_traceon_cmd = {
748 .name = "traceon",
749 .func = ftrace_trace_onoff_callback,
750};
751
752static struct ftrace_func_command ftrace_traceoff_cmd = {
753 .name = "traceoff",
754 .func = ftrace_trace_onoff_callback,
755};
756
757static struct ftrace_func_command ftrace_stacktrace_cmd = {
758 .name = "stacktrace",
759 .func = ftrace_stacktrace_callback,
760};
761
762static struct ftrace_func_command ftrace_dump_cmd = {
763 .name = "dump",
764 .func = ftrace_dump_callback,
765};
766
767static struct ftrace_func_command ftrace_cpudump_cmd = {
768 .name = "cpudump",
769 .func = ftrace_cpudump_callback,
770};
771
772static int __init init_func_cmd_traceon(void)
773{
774 int ret;
775
776 ret = register_ftrace_command(&ftrace_traceoff_cmd);
777 if (ret)
778 return ret;
779
780 ret = register_ftrace_command(&ftrace_traceon_cmd);
781 if (ret)
782 goto out_free_traceoff;
783
784 ret = register_ftrace_command(&ftrace_stacktrace_cmd);
785 if (ret)
786 goto out_free_traceon;
787
788 ret = register_ftrace_command(&ftrace_dump_cmd);
789 if (ret)
790 goto out_free_stacktrace;
791
792 ret = register_ftrace_command(&ftrace_cpudump_cmd);
793 if (ret)
794 goto out_free_dump;
795
796 return 0;
797
798 out_free_dump:
799 unregister_ftrace_command(&ftrace_dump_cmd);
800 out_free_stacktrace:
801 unregister_ftrace_command(&ftrace_stacktrace_cmd);
802 out_free_traceon:
803 unregister_ftrace_command(&ftrace_traceon_cmd);
804 out_free_traceoff:
805 unregister_ftrace_command(&ftrace_traceoff_cmd);
806
807 return ret;
808}
809#else
810static inline int init_func_cmd_traceon(void)
811{
812 return 0;
813}
814#endif /* CONFIG_DYNAMIC_FTRACE */
815
816__init int init_function_trace(void)
817{
818 init_func_cmd_traceon();
819 return register_tracer(&function_trace);
820}