diff options
Diffstat (limited to 'kernel/trace/trace_kdb.c')
| -rw-r--r-- | kernel/trace/trace_kdb.c | 136 | 
1 files changed, 136 insertions, 0 deletions
| diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c new file mode 100644 index 000000000000..7b8ecd751d93 --- /dev/null +++ b/kernel/trace/trace_kdb.c | |||
| @@ -0,0 +1,136 @@ | |||
| 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); | ||
