linux/kernel/trace/trace_kdb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * kdb helper for dumping the ftrace buffer
   4 *
   5 * Copyright (C) 2010 Jason Wessel <jason.wessel@windriver.com>
   6 *
   7 * ftrace_dump_buf based on ftrace_dump:
   8 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
   9 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
  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
  20static 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        static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
  25        struct trace_array *tr;
  26        unsigned int old_userobj;
  27        int cnt = 0, cpu;
  28
  29        trace_init_global_iter(&iter);
  30        iter.buffer_iter = buffer_iter;
  31        tr = iter.tr;
  32
  33        for_each_tracing_cpu(cpu) {
  34                atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
  35        }
  36
  37        old_userobj = tr->trace_flags;
  38
  39        /* don't look at user memory in panic mode */
  40        tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
  41
  42        kdb_printf("Dumping ftrace buffer:\n");
  43
  44        /* reset all but tr, trace, and overruns */
  45        memset(&iter.seq, 0,
  46                   sizeof(struct trace_iterator) -
  47                   offsetof(struct trace_iterator, seq));
  48        iter.iter_flags |= TRACE_FILE_LAT_FMT;
  49        iter.pos = -1;
  50
  51        if (cpu_file == RING_BUFFER_ALL_CPUS) {
  52                for_each_tracing_cpu(cpu) {
  53                        iter.buffer_iter[cpu] =
  54                        ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu);
  55                        ring_buffer_read_start(iter.buffer_iter[cpu]);
  56                        tracing_iter_reset(&iter, cpu);
  57                }
  58        } else {
  59                iter.cpu_file = cpu_file;
  60                iter.buffer_iter[cpu_file] =
  61                        ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu_file);
  62                ring_buffer_read_start(iter.buffer_iter[cpu_file]);
  63                tracing_iter_reset(&iter, cpu_file);
  64        }
  65
  66        while (trace_find_next_entry_inc(&iter)) {
  67                if (!cnt)
  68                        kdb_printf("---------------------------------\n");
  69                cnt++;
  70
  71                if (!skip_lines) {
  72                        print_trace_line(&iter);
  73                        trace_printk_seq(&iter.seq);
  74                } else {
  75                        skip_lines--;
  76                }
  77
  78                if (KDB_FLAG(CMD_INTERRUPT))
  79                        goto out;
  80        }
  81
  82        if (!cnt)
  83                kdb_printf("   (ftrace buffer empty)\n");
  84        else
  85                kdb_printf("---------------------------------\n");
  86
  87out:
  88        tr->trace_flags = old_userobj;
  89
  90        for_each_tracing_cpu(cpu) {
  91                atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
  92        }
  93
  94        for_each_tracing_cpu(cpu) {
  95                if (iter.buffer_iter[cpu]) {
  96                        ring_buffer_read_finish(iter.buffer_iter[cpu]);
  97                        iter.buffer_iter[cpu] = NULL;
  98                }
  99        }
 100}
 101
 102/*
 103 * kdb_ftdump - Dump the ftrace log buffer
 104 */
 105static int kdb_ftdump(int argc, const char **argv)
 106{
 107        int skip_lines = 0;
 108        long cpu_file;
 109        char *cp;
 110
 111        if (argc > 2)
 112                return KDB_ARGCOUNT;
 113
 114        if (argc) {
 115                skip_lines = simple_strtol(argv[1], &cp, 0);
 116                if (*cp)
 117                        skip_lines = 0;
 118        }
 119
 120        if (argc == 2) {
 121                cpu_file = simple_strtol(argv[2], &cp, 0);
 122                if (*cp || cpu_file >= NR_CPUS || cpu_file < 0 ||
 123                    !cpu_online(cpu_file))
 124                        return KDB_BADINT;
 125        } else {
 126                cpu_file = RING_BUFFER_ALL_CPUS;
 127        }
 128
 129        kdb_trap_printk++;
 130        ftrace_dump_buf(skip_lines, cpu_file);
 131        kdb_trap_printk--;
 132
 133        return 0;
 134}
 135
 136static __init int kdb_ftrace_register(void)
 137{
 138        kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
 139                            "Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);
 140        return 0;
 141}
 142
 143late_initcall(kdb_ftrace_register);
 144