aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/Makefile3
-rw-r--r--kernel/trace/trace.c43
-rw-r--r--kernel/trace/trace.h19
-rw-r--r--kernel/trace/trace_kdb.c136
4 files changed, 180 insertions, 21 deletions
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index ffb1a5b0550e..4215530b490b 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -57,5 +57,8 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
57obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o 57obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
58obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o 58obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o
59obj-$(CONFIG_EVENT_TRACING) += power-traces.o 59obj-$(CONFIG_EVENT_TRACING) += power-traces.o
60ifeq ($(CONFIG_TRACING),y)
61obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
62endif
60 63
61libftrace-y := ftrace.o 64libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 086d36316805..d6736b93dc2a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -101,10 +101,7 @@ static inline void ftrace_enable_cpu(void)
101 preempt_enable(); 101 preempt_enable();
102} 102}
103 103
104static cpumask_var_t __read_mostly tracing_buffer_mask; 104cpumask_var_t __read_mostly tracing_buffer_mask;
105
106#define for_each_tracing_cpu(cpu) \
107 for_each_cpu(cpu, tracing_buffer_mask)
108 105
109/* 106/*
110 * ftrace_dump_on_oops - variable to dump ftrace buffer on oops 107 * ftrace_dump_on_oops - variable to dump ftrace buffer on oops
@@ -1539,11 +1536,6 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
1539} 1536}
1540EXPORT_SYMBOL_GPL(trace_vprintk); 1537EXPORT_SYMBOL_GPL(trace_vprintk);
1541 1538
1542enum trace_file_type {
1543 TRACE_FILE_LAT_FMT = 1,
1544 TRACE_FILE_ANNOTATE = 2,
1545};
1546
1547static void trace_iterator_increment(struct trace_iterator *iter) 1539static void trace_iterator_increment(struct trace_iterator *iter)
1548{ 1540{
1549 /* Don't allow ftrace to trace into the ring buffers */ 1541 /* Don't allow ftrace to trace into the ring buffers */
@@ -1641,7 +1633,7 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
1641} 1633}
1642 1634
1643/* Find the next real entry, and increment the iterator to the next entry */ 1635/* Find the next real entry, and increment the iterator to the next entry */
1644static void *find_next_entry_inc(struct trace_iterator *iter) 1636void *trace_find_next_entry_inc(struct trace_iterator *iter)
1645{ 1637{
1646 iter->ent = __find_next_entry(iter, &iter->cpu, 1638 iter->ent = __find_next_entry(iter, &iter->cpu,
1647 &iter->lost_events, &iter->ts); 1639 &iter->lost_events, &iter->ts);
@@ -1676,19 +1668,19 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos)
1676 return NULL; 1668 return NULL;
1677 1669
1678 if (iter->idx < 0) 1670 if (iter->idx < 0)
1679 ent = find_next_entry_inc(iter); 1671 ent = trace_find_next_entry_inc(iter);
1680 else 1672 else
1681 ent = iter; 1673 ent = iter;
1682 1674
1683 while (ent && iter->idx < i) 1675 while (ent && iter->idx < i)
1684 ent = find_next_entry_inc(iter); 1676 ent = trace_find_next_entry_inc(iter);
1685 1677
1686 iter->pos = *pos; 1678 iter->pos = *pos;
1687 1679
1688 return ent; 1680 return ent;
1689} 1681}
1690 1682
1691static void tracing_iter_reset(struct trace_iterator *iter, int cpu) 1683void tracing_iter_reset(struct trace_iterator *iter, int cpu)
1692{ 1684{
1693 struct trace_array *tr = iter->tr; 1685 struct trace_array *tr = iter->tr;
1694 struct ring_buffer_event *event; 1686 struct ring_buffer_event *event;
@@ -2049,7 +2041,7 @@ int trace_empty(struct trace_iterator *iter)
2049} 2041}
2050 2042
2051/* Called with trace_event_read_lock() held. */ 2043/* Called with trace_event_read_lock() held. */
2052static enum print_line_t print_trace_line(struct trace_iterator *iter) 2044enum print_line_t print_trace_line(struct trace_iterator *iter)
2053{ 2045{
2054 enum print_line_t ret; 2046 enum print_line_t ret;
2055 2047
@@ -3211,7 +3203,7 @@ waitagain:
3211 3203
3212 trace_event_read_lock(); 3204 trace_event_read_lock();
3213 trace_access_lock(iter->cpu_file); 3205 trace_access_lock(iter->cpu_file);
3214 while (find_next_entry_inc(iter) != NULL) { 3206 while (trace_find_next_entry_inc(iter) != NULL) {
3215 enum print_line_t ret; 3207 enum print_line_t ret;
3216 int len = iter->seq.len; 3208 int len = iter->seq.len;
3217 3209
@@ -3294,7 +3286,7 @@ tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)
3294 if (ret != TRACE_TYPE_NO_CONSUME) 3286 if (ret != TRACE_TYPE_NO_CONSUME)
3295 trace_consume(iter); 3287 trace_consume(iter);
3296 rem -= count; 3288 rem -= count;
3297 if (!find_next_entry_inc(iter)) { 3289 if (!trace_find_next_entry_inc(iter)) {
3298 rem = 0; 3290 rem = 0;
3299 iter->ent = NULL; 3291 iter->ent = NULL;
3300 break; 3292 break;
@@ -3350,7 +3342,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
3350 if (ret <= 0) 3342 if (ret <= 0)
3351 goto out_err; 3343 goto out_err;
3352 3344
3353 if (!iter->ent && !find_next_entry_inc(iter)) { 3345 if (!iter->ent && !trace_find_next_entry_inc(iter)) {
3354 ret = -EFAULT; 3346 ret = -EFAULT;
3355 goto out_err; 3347 goto out_err;
3356 } 3348 }
@@ -4414,7 +4406,7 @@ static struct notifier_block trace_die_notifier = {
4414 */ 4406 */
4415#define KERN_TRACE KERN_EMERG 4407#define KERN_TRACE KERN_EMERG
4416 4408
4417static void 4409void
4418trace_printk_seq(struct trace_seq *s) 4410trace_printk_seq(struct trace_seq *s)
4419{ 4411{
4420 /* Probably should print a warning here. */ 4412 /* Probably should print a warning here. */
@@ -4429,6 +4421,13 @@ trace_printk_seq(struct trace_seq *s)
4429 trace_seq_init(s); 4421 trace_seq_init(s);
4430} 4422}
4431 4423
4424void trace_init_global_iter(struct trace_iterator *iter)
4425{
4426 iter->tr = &global_trace;
4427 iter->trace = current_trace;
4428 iter->cpu_file = TRACE_PIPE_ALL_CPU;
4429}
4430
4432static void 4431static void
4433__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) 4432__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
4434{ 4433{
@@ -4454,8 +4453,10 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
4454 if (disable_tracing) 4453 if (disable_tracing)
4455 ftrace_kill(); 4454 ftrace_kill();
4456 4455
4456 trace_init_global_iter(&iter);
4457
4457 for_each_tracing_cpu(cpu) { 4458 for_each_tracing_cpu(cpu) {
4458 atomic_inc(&global_trace.data[cpu]->disabled); 4459 atomic_inc(&iter.tr->data[cpu]->disabled);
4459 } 4460 }
4460 4461
4461 old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ; 4462 old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ;
@@ -4504,7 +4505,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
4504 iter.iter_flags |= TRACE_FILE_LAT_FMT; 4505 iter.iter_flags |= TRACE_FILE_LAT_FMT;
4505 iter.pos = -1; 4506 iter.pos = -1;
4506 4507
4507 if (find_next_entry_inc(&iter) != NULL) { 4508 if (trace_find_next_entry_inc(&iter) != NULL) {
4508 int ret; 4509 int ret;
4509 4510
4510 ret = print_trace_line(&iter); 4511 ret = print_trace_line(&iter);
@@ -4526,7 +4527,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
4526 trace_flags |= old_userobj; 4527 trace_flags |= old_userobj;
4527 4528
4528 for_each_tracing_cpu(cpu) { 4529 for_each_tracing_cpu(cpu) {
4529 atomic_dec(&global_trace.data[cpu]->disabled); 4530 atomic_dec(&iter.tr->data[cpu]->disabled);
4530 } 4531 }
4531 tracing_on(); 4532 tracing_on();
4532 } 4533 }
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2cd96399463f..0605fc00c176 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -338,6 +338,14 @@ struct trace_entry *tracing_get_trace_entry(struct trace_array *tr,
338struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, 338struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
339 int *ent_cpu, u64 *ent_ts); 339 int *ent_cpu, u64 *ent_ts);
340 340
341int trace_empty(struct trace_iterator *iter);
342
343void *trace_find_next_entry_inc(struct trace_iterator *iter);
344
345void trace_init_global_iter(struct trace_iterator *iter);
346
347void tracing_iter_reset(struct trace_iterator *iter, int cpu);
348
341void default_wait_pipe(struct trace_iterator *iter); 349void default_wait_pipe(struct trace_iterator *iter);
342void poll_wait_pipe(struct trace_iterator *iter); 350void poll_wait_pipe(struct trace_iterator *iter);
343 351
@@ -380,6 +388,15 @@ void tracing_start_sched_switch_record(void);
380int register_tracer(struct tracer *type); 388int register_tracer(struct tracer *type);
381void unregister_tracer(struct tracer *type); 389void unregister_tracer(struct tracer *type);
382int is_tracing_stopped(void); 390int is_tracing_stopped(void);
391enum trace_file_type {
392 TRACE_FILE_LAT_FMT = 1,
393 TRACE_FILE_ANNOTATE = 2,
394};
395
396extern cpumask_var_t __read_mostly tracing_buffer_mask;
397
398#define for_each_tracing_cpu(cpu) \
399 for_each_cpu(cpu, tracing_buffer_mask)
383 400
384extern int process_new_ksym_entry(char *ksymname, int op, unsigned long addr); 401extern int process_new_ksym_entry(char *ksymname, int op, unsigned long addr);
385 402
@@ -471,6 +488,8 @@ trace_array_vprintk(struct trace_array *tr,
471 unsigned long ip, const char *fmt, va_list args); 488 unsigned long ip, const char *fmt, va_list args);
472int trace_array_printk(struct trace_array *tr, 489int trace_array_printk(struct trace_array *tr,
473 unsigned long ip, const char *fmt, ...); 490 unsigned long ip, const char *fmt, ...);
491void trace_printk_seq(struct trace_seq *s);
492enum print_line_t print_trace_line(struct trace_iterator *iter);
474 493
475extern unsigned long trace_flags; 494extern unsigned long trace_flags;
476 495
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
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 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
83out:
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 */
98static 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
129static __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
136late_initcall(kdb_ftrace_register);