| 1 | |
| 2 | |
| 3 | * kdb helper for dumping the ftrace buffer
|
| 4 | *
|
| 5 | * Copyright (C) 2010 Jason Wessel <[email protected]>
|
| 6 | *
|
| 7 | * ftrace_dump_buf based on ftrace_dump:
|
| 8 | * Copyright (C) 2007-2008 Steven Rostedt <[email protected]>
|
| 9 | * Copyright (C) 2008 Ingo Molnar <[email protected]>
|
| 10 | *
|
| 11 |
|
| 12 | #include <linux/init.h>
|
| 13 | #include <linux/kgdb.h>
|
| 14 | #include <linux/kdb.h>
|
| 15 | #include <linux/ftrace.h>
|
| 16 |
|
| 17 | #include "trace.h"
|
| 18 | #include "trace_output.h"
|
| 19 |
|
| 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)
|
| 24 | {
|
| 25 | struct trace_array *tr;
|
| 26 | unsigned int old_userobj;
|
| 27 | int cnt = 0, cpu;
|
| 28 |
|
| 29 | tr = iter.tr;
|
| 30 |
|
| 31 | old_userobj = tr->trace_flags;
|
| 32 |
|
| 33 |
|
| 34 | tr->trace_flags &= ~TRACE_ITER(SYM_USEROBJ);
|
| 35 |
|
| 36 | kdb_printf("Dumping ftrace buffer:\n");
|
| 37 | if (skip_entries)
|
| 38 | kdb_printf("(skipping %d entries)\n", skip_entries);
|
| 39 |
|
| 40 | trace_iterator_reset(&iter);
|
| 41 | iter.iter_flags |= TRACE_FILE_LAT_FMT;
|
| 42 |
|
| 43 | if (cpu_file == RING_BUFFER_ALL_CPUS) {
|
| 44 | for_each_tracing_cpu(cpu) {
|
| 45 | iter.buffer_iter[cpu] =
|
| 46 | ring_buffer_read_start(iter.array_buffer->buffer,
|
| 47 | cpu, GFP_ATOMIC);
|
| 48 | tracing_iter_reset(&iter, cpu);
|
| 49 | }
|
| 50 | } else {
|
| 51 | iter.cpu_file = cpu_file;
|
| 52 | iter.buffer_iter[cpu_file] =
|
| 53 | ring_buffer_read_start(iter.array_buffer->buffer,
|
| 54 | cpu_file, GFP_ATOMIC);
|
| 55 | tracing_iter_reset(&iter, cpu_file);
|
| 56 | }
|
| 57 |
|
| 58 | while (trace_find_next_entry_inc(&iter)) {
|
| 59 | if (!cnt)
|
| 60 | kdb_printf("---------------------------------\n");
|
| 61 | cnt++;
|
| 62 |
|
| 63 | if (!skip_entries) {
|
| 64 | print_trace_line(&iter);
|
| 65 | trace_printk_seq(&iter.seq);
|
| 66 | } else {
|
| 67 | skip_entries--;
|
| 68 | }
|
| 69 |
|
| 70 | if (KDB_FLAG(CMD_INTERRUPT))
|
| 71 | goto out;
|
| 72 | }
|
| 73 |
|
| 74 | if (!cnt)
|
| 75 | kdb_printf(" (ftrace buffer empty)\n");
|
| 76 | else
|
| 77 | kdb_printf("---------------------------------\n");
|
| 78 |
|
| 79 | out:
|
| 80 | tr->trace_flags = old_userobj;
|
| 81 |
|
| 82 | for_each_tracing_cpu(cpu) {
|
| 83 | if (iter.buffer_iter[cpu]) {
|
| 84 | ring_buffer_read_finish(iter.buffer_iter[cpu]);
|
| 85 | iter.buffer_iter[cpu] = NULL;
|
| 86 | }
|
| 87 | }
|
| 88 | }
|
| 89 |
|
| 90 | |
| 91 | * kdb_ftdump - Dump the ftrace log buffer
|
| 92 |
|
| 93 | static int kdb_ftdump(int argc, const char **argv)
|
| 94 | {
|
| 95 | int skip_entries = 0;
|
| 96 | long cpu_file;
|
| 97 | int err;
|
| 98 | int cnt;
|
| 99 |
|
| 100 | if (argc > 2)
|
| 101 | return KDB_ARGCOUNT;
|
| 102 |
|
| 103 | if (argc && kstrtoint(argv[1], 0, &skip_entries))
|
| 104 | return KDB_BADINT;
|
| 105 |
|
| 106 | if (argc == 2) {
|
| 107 | err = kstrtol(argv[2], 0, &cpu_file);
|
| 108 | if (err || cpu_file >= NR_CPUS || cpu_file < 0 ||
|
| 109 | !cpu_online(cpu_file))
|
| 110 | return KDB_BADINT;
|
| 111 | } else {
|
| 112 | cpu_file = RING_BUFFER_ALL_CPUS;
|
| 113 | }
|
| 114 |
|
| 115 | kdb_trap_printk++;
|
| 116 |
|
| 117 | trace_init_global_iter(&iter);
|
| 118 | iter.buffer_iter = buffer_iter;
|
| 119 |
|
| 120 | tracer_tracing_disable(iter.tr);
|
| 121 |
|
| 122 |
|
| 123 | if (skip_entries < 0) {
|
| 124 | if (cpu_file == RING_BUFFER_ALL_CPUS)
|
| 125 | cnt = trace_total_entries(NULL);
|
| 126 | else
|
| 127 | cnt = trace_total_entries_cpu(NULL, cpu_file);
|
| 128 | skip_entries = max(cnt + skip_entries, 0);
|
| 129 | }
|
| 130 |
|
| 131 | ftrace_dump_buf(skip_entries, cpu_file);
|
| 132 |
|
| 133 | tracer_tracing_enable(iter.tr);
|
| 134 |
|
| 135 | kdb_trap_printk--;
|
| 136 |
|
| 137 | return 0;
|
| 138 | }
|
| 139 |
|
| 140 | static kdbtab_t ftdump_cmd = {
|
| 141 | .name = "ftdump",
|
| 142 | .func = kdb_ftdump,
|
| 143 | .usage = "[skip_#entries] [cpu]",
|
| 144 | .help = "Dump ftrace log; -skip dumps last #entries",
|
| 145 | .flags = KDB_ENABLE_ALWAYS_SAFE,
|
| 146 | };
|
| 147 |
|
| 148 | static __init int kdb_ftrace_register(void)
|
| 149 | {
|
| 150 | kdb_register(&ftdump_cmd);
|
| 151 | return 0;
|
| 152 | }
|
| 153 |
|
| 154 | late_initcall(kdb_ftrace_register);
|