1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2955b61e5SJason Wessel /*
3955b61e5SJason Wessel * kdb helper for dumping the ftrace buffer
4955b61e5SJason Wessel *
5955b61e5SJason Wessel * Copyright (C) 2010 Jason Wessel <jason.wessel@windriver.com>
6955b61e5SJason Wessel *
7955b61e5SJason Wessel * ftrace_dump_buf based on ftrace_dump:
8955b61e5SJason Wessel * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
9955b61e5SJason Wessel * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
10955b61e5SJason Wessel *
11955b61e5SJason Wessel */
12955b61e5SJason Wessel #include <linux/init.h>
13955b61e5SJason Wessel #include <linux/kgdb.h>
14955b61e5SJason Wessel #include <linux/kdb.h>
15955b61e5SJason Wessel #include <linux/ftrace.h>
16955b61e5SJason Wessel
17955b61e5SJason Wessel #include "trace.h"
18955b61e5SJason Wessel #include "trace_output.h"
19955b61e5SJason Wessel
20955b61e5SJason Wessel static struct trace_iterator iter;
21c270cc75SDaniel Thompson static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
2203197fc0SDouglas Anderson
ftrace_dump_buf(int skip_entries,long cpu_file)2303197fc0SDouglas Anderson static void ftrace_dump_buf(int skip_entries, long cpu_file)
2403197fc0SDouglas Anderson {
25983f938aSSteven Rostedt (Red Hat) struct trace_array *tr;
26955b61e5SJason Wessel unsigned int old_userobj;
27955b61e5SJason Wessel int cnt = 0, cpu;
28955b61e5SJason Wessel
29983f938aSSteven Rostedt (Red Hat) tr = iter.tr;
30955b61e5SJason Wessel
31983f938aSSteven Rostedt (Red Hat) old_userobj = tr->trace_flags;
32955b61e5SJason Wessel
33955b61e5SJason Wessel /* don't look at user memory in panic mode */
34983f938aSSteven Rostedt (Red Hat) tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
35955b61e5SJason Wessel
36955b61e5SJason Wessel kdb_printf("Dumping ftrace buffer:\n");
3703197fc0SDouglas Anderson if (skip_entries)
3803197fc0SDouglas Anderson kdb_printf("(skipping %d entries)\n", skip_entries);
39955b61e5SJason Wessel
400c97bf86SMiguel Ojeda trace_iterator_reset(&iter);
41955b61e5SJason Wessel iter.iter_flags |= TRACE_FILE_LAT_FMT;
42955b61e5SJason Wessel
43ae3b5093SSteven Rostedt if (cpu_file == RING_BUFFER_ALL_CPUS) {
44955b61e5SJason Wessel for_each_tracing_cpu(cpu) {
45955b61e5SJason Wessel iter.buffer_iter[cpu] =
461c5eb448SSteven Rostedt (VMware) ring_buffer_read_prepare(iter.array_buffer->buffer,
4731b265b3SDouglas Anderson cpu, GFP_ATOMIC);
48955b61e5SJason Wessel ring_buffer_read_start(iter.buffer_iter[cpu]);
49955b61e5SJason Wessel tracing_iter_reset(&iter, cpu);
50955b61e5SJason Wessel }
5119063c77SJason Wessel } else {
5219063c77SJason Wessel iter.cpu_file = cpu_file;
5319063c77SJason Wessel iter.buffer_iter[cpu_file] =
541c5eb448SSteven Rostedt (VMware) ring_buffer_read_prepare(iter.array_buffer->buffer,
5531b265b3SDouglas Anderson cpu_file, GFP_ATOMIC);
5619063c77SJason Wessel ring_buffer_read_start(iter.buffer_iter[cpu_file]);
5719063c77SJason Wessel tracing_iter_reset(&iter, cpu_file);
5819063c77SJason Wessel }
598520dedbSDaniel Thompson
608520dedbSDaniel Thompson while (trace_find_next_entry_inc(&iter)) {
61955b61e5SJason Wessel if (!cnt)
62955b61e5SJason Wessel kdb_printf("---------------------------------\n");
63955b61e5SJason Wessel cnt++;
64955b61e5SJason Wessel
65dbfe6733SDouglas Anderson if (!skip_entries) {
66955b61e5SJason Wessel print_trace_line(&iter);
67955b61e5SJason Wessel trace_printk_seq(&iter.seq);
688520dedbSDaniel Thompson } else {
69dbfe6733SDouglas Anderson skip_entries--;
708520dedbSDaniel Thompson }
718520dedbSDaniel Thompson
72955b61e5SJason Wessel if (KDB_FLAG(CMD_INTERRUPT))
73955b61e5SJason Wessel goto out;
74955b61e5SJason Wessel }
75955b61e5SJason Wessel
76955b61e5SJason Wessel if (!cnt)
77955b61e5SJason Wessel kdb_printf(" (ftrace buffer empty)\n");
78955b61e5SJason Wessel else
79955b61e5SJason Wessel kdb_printf("---------------------------------\n");
80955b61e5SJason Wessel
81955b61e5SJason Wessel out:
82983f938aSSteven Rostedt (Red Hat) tr->trace_flags = old_userobj;
83955b61e5SJason Wessel
84955b61e5SJason Wessel for_each_tracing_cpu(cpu) {
85c270cc75SDaniel Thompson if (iter.buffer_iter[cpu]) {
86955b61e5SJason Wessel ring_buffer_read_finish(iter.buffer_iter[cpu]);
87c270cc75SDaniel Thompson iter.buffer_iter[cpu] = NULL;
88c270cc75SDaniel Thompson }
89c270cc75SDaniel Thompson }
90955b61e5SJason Wessel }
91955b61e5SJason Wessel
92955b61e5SJason Wessel /*
93955b61e5SJason Wessel * kdb_ftdump - Dump the ftrace log buffer
94955b61e5SJason Wessel */
kdb_ftdump(int argc,const char ** argv)95955b61e5SJason Wessel static int kdb_ftdump(int argc, const char **argv)
96955b61e5SJason Wessel {
97dbfe6733SDouglas Anderson int skip_entries = 0;
9819063c77SJason Wessel long cpu_file;
99955b61e5SJason Wessel char *cp;
10003197fc0SDouglas Anderson int cnt;
10103197fc0SDouglas Anderson int cpu;
102955b61e5SJason Wessel
10319063c77SJason Wessel if (argc > 2)
104955b61e5SJason Wessel return KDB_ARGCOUNT;
105955b61e5SJason Wessel
106955b61e5SJason Wessel if (argc) {
107dbfe6733SDouglas Anderson skip_entries = simple_strtol(argv[1], &cp, 0);
108955b61e5SJason Wessel if (*cp)
109dbfe6733SDouglas Anderson skip_entries = 0;
110955b61e5SJason Wessel }
111955b61e5SJason Wessel
11219063c77SJason Wessel if (argc == 2) {
11319063c77SJason Wessel cpu_file = simple_strtol(argv[2], &cp, 0);
11419063c77SJason Wessel if (*cp || cpu_file >= NR_CPUS || cpu_file < 0 ||
11519063c77SJason Wessel !cpu_online(cpu_file))
11619063c77SJason Wessel return KDB_BADINT;
11719063c77SJason Wessel } else {
118ae3b5093SSteven Rostedt cpu_file = RING_BUFFER_ALL_CPUS;
11919063c77SJason Wessel }
12019063c77SJason Wessel
121955b61e5SJason Wessel kdb_trap_printk++;
12203197fc0SDouglas Anderson
12303197fc0SDouglas Anderson trace_init_global_iter(&iter);
12403197fc0SDouglas Anderson iter.buffer_iter = buffer_iter;
12503197fc0SDouglas Anderson
12603197fc0SDouglas Anderson for_each_tracing_cpu(cpu) {
1271c5eb448SSteven Rostedt (VMware) atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
12803197fc0SDouglas Anderson }
12903197fc0SDouglas Anderson
13003197fc0SDouglas Anderson /* A negative skip_entries means skip all but the last entries */
13103197fc0SDouglas Anderson if (skip_entries < 0) {
13203197fc0SDouglas Anderson if (cpu_file == RING_BUFFER_ALL_CPUS)
13303197fc0SDouglas Anderson cnt = trace_total_entries(NULL);
13403197fc0SDouglas Anderson else
13503197fc0SDouglas Anderson cnt = trace_total_entries_cpu(NULL, cpu_file);
13603197fc0SDouglas Anderson skip_entries = max(cnt + skip_entries, 0);
13703197fc0SDouglas Anderson }
13803197fc0SDouglas Anderson
139dbfe6733SDouglas Anderson ftrace_dump_buf(skip_entries, cpu_file);
14003197fc0SDouglas Anderson
14103197fc0SDouglas Anderson for_each_tracing_cpu(cpu) {
1421c5eb448SSteven Rostedt (VMware) atomic_dec(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
14303197fc0SDouglas Anderson }
14403197fc0SDouglas Anderson
145955b61e5SJason Wessel kdb_trap_printk--;
146955b61e5SJason Wessel
147955b61e5SJason Wessel return 0;
148955b61e5SJason Wessel }
149955b61e5SJason Wessel
150c25abcd6SSumit Garg static kdbtab_t ftdump_cmd = {
151*e868f0a3SSumit Garg .name = "ftdump",
152*e868f0a3SSumit Garg .func = kdb_ftdump,
153*e868f0a3SSumit Garg .usage = "[skip_#entries] [cpu]",
154*e868f0a3SSumit Garg .help = "Dump ftrace log; -skip dumps last #entries",
155*e868f0a3SSumit Garg .flags = KDB_ENABLE_ALWAYS_SAFE,
156c25abcd6SSumit Garg };
157c25abcd6SSumit Garg
kdb_ftrace_register(void)158955b61e5SJason Wessel static __init int kdb_ftrace_register(void)
159955b61e5SJason Wessel {
160c25abcd6SSumit Garg kdb_register(&ftdump_cmd);
161955b61e5SJason Wessel return 0;
162955b61e5SJason Wessel }
163955b61e5SJason Wessel
164955b61e5SJason Wessel late_initcall(kdb_ftrace_register);
165