.. | .. |
---|
17 | 17 | #include "trace.h" |
---|
18 | 18 | #include "trace_output.h" |
---|
19 | 19 | |
---|
20 | | -static void ftrace_dump_buf(int skip_lines, long cpu_file) |
---|
| 20 | +static struct trace_iterator iter; |
---|
| 21 | +static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS]; |
---|
| 22 | + |
---|
| 23 | +static void ftrace_dump_buf(int skip_entries, long cpu_file) |
---|
21 | 24 | { |
---|
22 | | - /* use static because iter can be a bit big for the stack */ |
---|
23 | | - static struct trace_iterator iter; |
---|
24 | | - static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS]; |
---|
25 | 25 | struct trace_array *tr; |
---|
26 | 26 | unsigned int old_userobj; |
---|
27 | 27 | int cnt = 0, cpu; |
---|
28 | 28 | |
---|
29 | | - trace_init_global_iter(&iter); |
---|
30 | | - iter.buffer_iter = buffer_iter; |
---|
31 | 29 | tr = iter.tr; |
---|
32 | | - |
---|
33 | | - for_each_tracing_cpu(cpu) { |
---|
34 | | - atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); |
---|
35 | | - } |
---|
36 | 30 | |
---|
37 | 31 | old_userobj = tr->trace_flags; |
---|
38 | 32 | |
---|
.. | .. |
---|
40 | 34 | tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ; |
---|
41 | 35 | |
---|
42 | 36 | kdb_printf("Dumping ftrace buffer:\n"); |
---|
| 37 | + if (skip_entries) |
---|
| 38 | + kdb_printf("(skipping %d entries)\n", skip_entries); |
---|
43 | 39 | |
---|
44 | 40 | trace_iterator_reset(&iter); |
---|
45 | 41 | iter.iter_flags |= TRACE_FILE_LAT_FMT; |
---|
.. | .. |
---|
47 | 43 | if (cpu_file == RING_BUFFER_ALL_CPUS) { |
---|
48 | 44 | for_each_tracing_cpu(cpu) { |
---|
49 | 45 | iter.buffer_iter[cpu] = |
---|
50 | | - ring_buffer_read_prepare(iter.trace_buffer->buffer, |
---|
| 46 | + ring_buffer_read_prepare(iter.array_buffer->buffer, |
---|
51 | 47 | cpu, GFP_ATOMIC); |
---|
52 | 48 | ring_buffer_read_start(iter.buffer_iter[cpu]); |
---|
53 | 49 | tracing_iter_reset(&iter, cpu); |
---|
.. | .. |
---|
55 | 51 | } else { |
---|
56 | 52 | iter.cpu_file = cpu_file; |
---|
57 | 53 | iter.buffer_iter[cpu_file] = |
---|
58 | | - ring_buffer_read_prepare(iter.trace_buffer->buffer, |
---|
| 54 | + ring_buffer_read_prepare(iter.array_buffer->buffer, |
---|
59 | 55 | cpu_file, GFP_ATOMIC); |
---|
60 | 56 | ring_buffer_read_start(iter.buffer_iter[cpu_file]); |
---|
61 | 57 | tracing_iter_reset(&iter, cpu_file); |
---|
.. | .. |
---|
66 | 62 | kdb_printf("---------------------------------\n"); |
---|
67 | 63 | cnt++; |
---|
68 | 64 | |
---|
69 | | - if (!skip_lines) { |
---|
| 65 | + if (!skip_entries) { |
---|
70 | 66 | print_trace_line(&iter); |
---|
71 | 67 | trace_printk_seq(&iter.seq); |
---|
72 | 68 | } else { |
---|
73 | | - skip_lines--; |
---|
| 69 | + skip_entries--; |
---|
74 | 70 | } |
---|
75 | 71 | |
---|
76 | 72 | if (KDB_FLAG(CMD_INTERRUPT)) |
---|
.. | .. |
---|
86 | 82 | tr->trace_flags = old_userobj; |
---|
87 | 83 | |
---|
88 | 84 | for_each_tracing_cpu(cpu) { |
---|
89 | | - atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); |
---|
90 | | - } |
---|
91 | | - |
---|
92 | | - for_each_tracing_cpu(cpu) { |
---|
93 | 85 | if (iter.buffer_iter[cpu]) { |
---|
94 | 86 | ring_buffer_read_finish(iter.buffer_iter[cpu]); |
---|
95 | 87 | iter.buffer_iter[cpu] = NULL; |
---|
.. | .. |
---|
102 | 94 | */ |
---|
103 | 95 | static int kdb_ftdump(int argc, const char **argv) |
---|
104 | 96 | { |
---|
105 | | - int skip_lines = 0; |
---|
| 97 | + int skip_entries = 0; |
---|
106 | 98 | long cpu_file; |
---|
107 | 99 | char *cp; |
---|
| 100 | + int cnt; |
---|
| 101 | + int cpu; |
---|
108 | 102 | |
---|
109 | 103 | if (argc > 2) |
---|
110 | 104 | return KDB_ARGCOUNT; |
---|
111 | 105 | |
---|
112 | 106 | if (argc) { |
---|
113 | | - skip_lines = simple_strtol(argv[1], &cp, 0); |
---|
| 107 | + skip_entries = simple_strtol(argv[1], &cp, 0); |
---|
114 | 108 | if (*cp) |
---|
115 | | - skip_lines = 0; |
---|
| 109 | + skip_entries = 0; |
---|
116 | 110 | } |
---|
117 | 111 | |
---|
118 | 112 | if (argc == 2) { |
---|
.. | .. |
---|
125 | 119 | } |
---|
126 | 120 | |
---|
127 | 121 | kdb_trap_printk++; |
---|
128 | | - ftrace_dump_buf(skip_lines, cpu_file); |
---|
| 122 | + |
---|
| 123 | + trace_init_global_iter(&iter); |
---|
| 124 | + iter.buffer_iter = buffer_iter; |
---|
| 125 | + |
---|
| 126 | + for_each_tracing_cpu(cpu) { |
---|
| 127 | + atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled); |
---|
| 128 | + } |
---|
| 129 | + |
---|
| 130 | + /* A negative skip_entries means skip all but the last entries */ |
---|
| 131 | + if (skip_entries < 0) { |
---|
| 132 | + if (cpu_file == RING_BUFFER_ALL_CPUS) |
---|
| 133 | + cnt = trace_total_entries(NULL); |
---|
| 134 | + else |
---|
| 135 | + cnt = trace_total_entries_cpu(NULL, cpu_file); |
---|
| 136 | + skip_entries = max(cnt + skip_entries, 0); |
---|
| 137 | + } |
---|
| 138 | + |
---|
| 139 | + ftrace_dump_buf(skip_entries, cpu_file); |
---|
| 140 | + |
---|
| 141 | + for_each_tracing_cpu(cpu) { |
---|
| 142 | + atomic_dec(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled); |
---|
| 143 | + } |
---|
| 144 | + |
---|
129 | 145 | kdb_trap_printk--; |
---|
130 | 146 | |
---|
131 | 147 | return 0; |
---|
.. | .. |
---|
133 | 149 | |
---|
134 | 150 | static __init int kdb_ftrace_register(void) |
---|
135 | 151 | { |
---|
136 | | - kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]", |
---|
137 | | - "Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE); |
---|
| 152 | + kdb_register_flags("ftdump", kdb_ftdump, "[skip_#entries] [cpu]", |
---|
| 153 | + "Dump ftrace log; -skip dumps last #entries", 0, |
---|
| 154 | + KDB_ENABLE_ALWAYS_SAFE); |
---|
138 | 155 | return 0; |
---|
139 | 156 | } |
---|
140 | 157 | |
---|