| .. | .. |
|---|
| 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 | |
|---|