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