xref: /openbmc/linux/kernel/trace/trace_kdb.c (revision 95e9fd10)
1 /*
2  * kdb helper for dumping the ftrace buffer
3  *
4  * Copyright (C) 2010 Jason Wessel <jason.wessel@windriver.com>
5  *
6  * ftrace_dump_buf based on ftrace_dump:
7  * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
8  * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
9  *
10  */
11 #include <linux/init.h>
12 #include <linux/kgdb.h>
13 #include <linux/kdb.h>
14 #include <linux/ftrace.h>
15 
16 #include "trace.h"
17 #include "trace_output.h"
18 
19 static void ftrace_dump_buf(int skip_lines, long cpu_file)
20 {
21 	/* use static because iter can be a bit big for the stack */
22 	static struct trace_iterator iter;
23 	unsigned int old_userobj;
24 	int cnt = 0, cpu;
25 
26 	trace_init_global_iter(&iter);
27 
28 	for_each_tracing_cpu(cpu) {
29 		atomic_inc(&iter.tr->data[cpu]->disabled);
30 	}
31 
32 	old_userobj = trace_flags;
33 
34 	/* don't look at user memory in panic mode */
35 	trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
36 
37 	kdb_printf("Dumping ftrace buffer:\n");
38 
39 	/* reset all but tr, trace, and overruns */
40 	memset(&iter.seq, 0,
41 		   sizeof(struct trace_iterator) -
42 		   offsetof(struct trace_iterator, seq));
43 	iter.iter_flags |= TRACE_FILE_LAT_FMT;
44 	iter.pos = -1;
45 
46 	if (cpu_file == TRACE_PIPE_ALL_CPU) {
47 		for_each_tracing_cpu(cpu) {
48 			iter.buffer_iter[cpu] =
49 			ring_buffer_read_prepare(iter.tr->buffer, cpu);
50 			ring_buffer_read_start(iter.buffer_iter[cpu]);
51 			tracing_iter_reset(&iter, cpu);
52 		}
53 	} else {
54 		iter.cpu_file = cpu_file;
55 		iter.buffer_iter[cpu_file] =
56 			ring_buffer_read_prepare(iter.tr->buffer, cpu_file);
57 		ring_buffer_read_start(iter.buffer_iter[cpu_file]);
58 		tracing_iter_reset(&iter, cpu_file);
59 	}
60 	if (!trace_empty(&iter))
61 		trace_find_next_entry_inc(&iter);
62 	while (!trace_empty(&iter)) {
63 		if (!cnt)
64 			kdb_printf("---------------------------------\n");
65 		cnt++;
66 
67 		if (trace_find_next_entry_inc(&iter) != NULL && !skip_lines)
68 			print_trace_line(&iter);
69 		if (!skip_lines)
70 			trace_printk_seq(&iter.seq);
71 		else
72 			skip_lines--;
73 		if (KDB_FLAG(CMD_INTERRUPT))
74 			goto out;
75 	}
76 
77 	if (!cnt)
78 		kdb_printf("   (ftrace buffer empty)\n");
79 	else
80 		kdb_printf("---------------------------------\n");
81 
82 out:
83 	trace_flags = old_userobj;
84 
85 	for_each_tracing_cpu(cpu) {
86 		atomic_dec(&iter.tr->data[cpu]->disabled);
87 	}
88 
89 	for_each_tracing_cpu(cpu)
90 		if (iter.buffer_iter[cpu])
91 			ring_buffer_read_finish(iter.buffer_iter[cpu]);
92 }
93 
94 /*
95  * kdb_ftdump - Dump the ftrace log buffer
96  */
97 static int kdb_ftdump(int argc, const char **argv)
98 {
99 	int skip_lines = 0;
100 	long cpu_file;
101 	char *cp;
102 
103 	if (argc > 2)
104 		return KDB_ARGCOUNT;
105 
106 	if (argc) {
107 		skip_lines = simple_strtol(argv[1], &cp, 0);
108 		if (*cp)
109 			skip_lines = 0;
110 	}
111 
112 	if (argc == 2) {
113 		cpu_file = simple_strtol(argv[2], &cp, 0);
114 		if (*cp || cpu_file >= NR_CPUS || cpu_file < 0 ||
115 		    !cpu_online(cpu_file))
116 			return KDB_BADINT;
117 	} else {
118 		cpu_file = TRACE_PIPE_ALL_CPU;
119 	}
120 
121 	kdb_trap_printk++;
122 	ftrace_dump_buf(skip_lines, cpu_file);
123 	kdb_trap_printk--;
124 
125 	return 0;
126 }
127 
128 static __init int kdb_ftrace_register(void)
129 {
130 	kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
131 			    "Dump ftrace log", 0, KDB_REPEAT_NONE);
132 	return 0;
133 }
134 
135 late_initcall(kdb_ftrace_register);
136