xref: /linux-6.15/kernel/trace/trace_kdb.c (revision 0c10cc24)
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 <[email protected]>
6955b61e5SJason Wessel  *
7955b61e5SJason Wessel  * ftrace_dump_buf based on ftrace_dump:
8955b61e5SJason Wessel  * Copyright (C) 2007-2008 Steven Rostedt <[email protected]>
9955b61e5SJason Wessel  * Copyright (C) 2008 Ingo Molnar <[email protected]>
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;
99*0c10cc24SYuran Pereira 	int err;
10003197fc0SDouglas Anderson 	int cnt;
10103197fc0SDouglas Anderson 	int cpu;
102955b61e5SJason Wessel 
10319063c77SJason Wessel 	if (argc > 2)
104955b61e5SJason Wessel 		return KDB_ARGCOUNT;
105955b61e5SJason Wessel 
106*0c10cc24SYuran Pereira 	if (argc && kstrtoint(argv[1], 0, &skip_entries))
107*0c10cc24SYuran Pereira 		return KDB_BADINT;
108955b61e5SJason Wessel 
10919063c77SJason Wessel 	if (argc == 2) {
110*0c10cc24SYuran Pereira 		err = kstrtol(argv[2], 0, &cpu_file);
111*0c10cc24SYuran Pereira 		if (err || cpu_file >= NR_CPUS || cpu_file < 0 ||
11219063c77SJason Wessel 		    !cpu_online(cpu_file))
11319063c77SJason Wessel 			return KDB_BADINT;
11419063c77SJason Wessel 	} else {
115ae3b5093SSteven Rostedt 		cpu_file = RING_BUFFER_ALL_CPUS;
11619063c77SJason Wessel 	}
11719063c77SJason Wessel 
118955b61e5SJason Wessel 	kdb_trap_printk++;
11903197fc0SDouglas Anderson 
12003197fc0SDouglas Anderson 	trace_init_global_iter(&iter);
12103197fc0SDouglas Anderson 	iter.buffer_iter = buffer_iter;
12203197fc0SDouglas Anderson 
12303197fc0SDouglas Anderson 	for_each_tracing_cpu(cpu) {
1241c5eb448SSteven Rostedt (VMware) 		atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
12503197fc0SDouglas Anderson 	}
12603197fc0SDouglas Anderson 
12703197fc0SDouglas Anderson 	/* A negative skip_entries means skip all but the last entries */
12803197fc0SDouglas Anderson 	if (skip_entries < 0) {
12903197fc0SDouglas Anderson 		if (cpu_file == RING_BUFFER_ALL_CPUS)
13003197fc0SDouglas Anderson 			cnt = trace_total_entries(NULL);
13103197fc0SDouglas Anderson 		else
13203197fc0SDouglas Anderson 			cnt = trace_total_entries_cpu(NULL, cpu_file);
13303197fc0SDouglas Anderson 		skip_entries = max(cnt + skip_entries, 0);
13403197fc0SDouglas Anderson 	}
13503197fc0SDouglas Anderson 
136dbfe6733SDouglas Anderson 	ftrace_dump_buf(skip_entries, cpu_file);
13703197fc0SDouglas Anderson 
13803197fc0SDouglas Anderson 	for_each_tracing_cpu(cpu) {
1391c5eb448SSteven Rostedt (VMware) 		atomic_dec(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
14003197fc0SDouglas Anderson 	}
14103197fc0SDouglas Anderson 
142955b61e5SJason Wessel 	kdb_trap_printk--;
143955b61e5SJason Wessel 
144955b61e5SJason Wessel 	return 0;
145955b61e5SJason Wessel }
146955b61e5SJason Wessel 
147c25abcd6SSumit Garg static kdbtab_t ftdump_cmd = {
148e868f0a3SSumit Garg 	.name = "ftdump",
149e868f0a3SSumit Garg 	.func = kdb_ftdump,
150e868f0a3SSumit Garg 	.usage = "[skip_#entries] [cpu]",
151e868f0a3SSumit Garg 	.help = "Dump ftrace log; -skip dumps last #entries",
152e868f0a3SSumit Garg 	.flags = KDB_ENABLE_ALWAYS_SAFE,
153c25abcd6SSumit Garg };
154c25abcd6SSumit Garg 
kdb_ftrace_register(void)155955b61e5SJason Wessel static __init int kdb_ftrace_register(void)
156955b61e5SJason Wessel {
157c25abcd6SSumit Garg 	kdb_register(&ftdump_cmd);
158955b61e5SJason Wessel 	return 0;
159955b61e5SJason Wessel }
160955b61e5SJason Wessel 
161955b61e5SJason Wessel late_initcall(kdb_ftrace_register);
162