diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 13:31:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 13:31:35 -0400 |
commit | af5329cdf51cdd208a323e521faa46800a16d2ec (patch) | |
tree | 33eac56aac120778dc04207290ad539765ff5eb6 /kernel | |
parent | 1dc60c53d36b08f361e1a2767c41196acce96d08 (diff) | |
parent | 7798ed0f57b4d137e660fbf5be1e1528e40f89ac (diff) |
Merge branch 'core/stacktrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'core/stacktrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
generic-ipi: powerpc/generic-ipi tree build failure
stacktrace: fix build failure on sparc64
stacktrace: export save_stack_trace[_tsk]
stacktrace: fix modular build, export print_stack_trace and save_stack_trace
backtrace: replace timer with tasklet + completions
stacktrace: add saved stack traces to backtrace self-test
stacktrace: print_stack_trace() cleanup
debugging: make stacktrace independent from DEBUG_KERNEL
stacktrace: don't crash on invalid stack trace structs
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/backtracetest.c | 65 | ||||
-rw-r--r-- | kernel/stacktrace.c | 14 |
2 files changed, 62 insertions, 17 deletions
diff --git a/kernel/backtracetest.c b/kernel/backtracetest.c index d1a7605c5b8f..a5e026bc45c4 100644 --- a/kernel/backtracetest.c +++ b/kernel/backtracetest.c | |||
@@ -10,30 +10,73 @@ | |||
10 | * of the License. | 10 | * of the License. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/completion.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/interrupt.h> | ||
13 | #include <linux/module.h> | 16 | #include <linux/module.h> |
14 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
15 | #include <linux/delay.h> | 18 | #include <linux/stacktrace.h> |
19 | |||
20 | static void backtrace_test_normal(void) | ||
21 | { | ||
22 | printk("Testing a backtrace from process context.\n"); | ||
23 | printk("The following trace is a kernel self test and not a bug!\n"); | ||
16 | 24 | ||
17 | static struct timer_list backtrace_timer; | 25 | dump_stack(); |
26 | } | ||
18 | 27 | ||
19 | static void backtrace_test_timer(unsigned long data) | 28 | static DECLARE_COMPLETION(backtrace_work); |
29 | |||
30 | static void backtrace_test_irq_callback(unsigned long data) | ||
31 | { | ||
32 | dump_stack(); | ||
33 | complete(&backtrace_work); | ||
34 | } | ||
35 | |||
36 | static DECLARE_TASKLET(backtrace_tasklet, &backtrace_test_irq_callback, 0); | ||
37 | |||
38 | static void backtrace_test_irq(void) | ||
20 | { | 39 | { |
21 | printk("Testing a backtrace from irq context.\n"); | 40 | printk("Testing a backtrace from irq context.\n"); |
22 | printk("The following trace is a kernel self test and not a bug!\n"); | 41 | printk("The following trace is a kernel self test and not a bug!\n"); |
23 | dump_stack(); | 42 | |
43 | init_completion(&backtrace_work); | ||
44 | tasklet_schedule(&backtrace_tasklet); | ||
45 | wait_for_completion(&backtrace_work); | ||
46 | } | ||
47 | |||
48 | #ifdef CONFIG_STACKTRACE | ||
49 | static void backtrace_test_saved(void) | ||
50 | { | ||
51 | struct stack_trace trace; | ||
52 | unsigned long entries[8]; | ||
53 | |||
54 | printk("Testing a saved backtrace.\n"); | ||
55 | printk("The following trace is a kernel self test and not a bug!\n"); | ||
56 | |||
57 | trace.nr_entries = 0; | ||
58 | trace.max_entries = ARRAY_SIZE(entries); | ||
59 | trace.entries = entries; | ||
60 | trace.skip = 0; | ||
61 | |||
62 | save_stack_trace(&trace); | ||
63 | print_stack_trace(&trace, 0); | ||
64 | } | ||
65 | #else | ||
66 | static void backtrace_test_saved(void) | ||
67 | { | ||
68 | printk("Saved backtrace test skipped.\n"); | ||
24 | } | 69 | } |
70 | #endif | ||
71 | |||
25 | static int backtrace_regression_test(void) | 72 | static int backtrace_regression_test(void) |
26 | { | 73 | { |
27 | printk("====[ backtrace testing ]===========\n"); | 74 | printk("====[ backtrace testing ]===========\n"); |
28 | printk("Testing a backtrace from process context.\n"); | ||
29 | printk("The following trace is a kernel self test and not a bug!\n"); | ||
30 | dump_stack(); | ||
31 | 75 | ||
32 | init_timer(&backtrace_timer); | 76 | backtrace_test_normal(); |
33 | backtrace_timer.function = backtrace_test_timer; | 77 | backtrace_test_irq(); |
34 | mod_timer(&backtrace_timer, jiffies + 10); | 78 | backtrace_test_saved(); |
35 | 79 | ||
36 | msleep(10); | ||
37 | printk("====[ end of backtrace testing ]====\n"); | 80 | printk("====[ end of backtrace testing ]====\n"); |
38 | return 0; | 81 | return 0; |
39 | } | 82 | } |
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c index b71816e47a30..94b527ef1d1e 100644 --- a/kernel/stacktrace.c +++ b/kernel/stacktrace.c | |||
@@ -6,19 +6,21 @@ | |||
6 | * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> | 6 | * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> |
7 | */ | 7 | */ |
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | #include <linux/module.h> | ||
9 | #include <linux/kallsyms.h> | 10 | #include <linux/kallsyms.h> |
10 | #include <linux/stacktrace.h> | 11 | #include <linux/stacktrace.h> |
11 | 12 | ||
12 | void print_stack_trace(struct stack_trace *trace, int spaces) | 13 | void print_stack_trace(struct stack_trace *trace, int spaces) |
13 | { | 14 | { |
14 | int i, j; | 15 | int i; |
15 | 16 | ||
16 | for (i = 0; i < trace->nr_entries; i++) { | 17 | if (WARN_ON(!trace->entries)) |
17 | unsigned long ip = trace->entries[i]; | 18 | return; |
18 | 19 | ||
19 | for (j = 0; j < spaces + 1; j++) | 20 | for (i = 0; i < trace->nr_entries; i++) { |
20 | printk(" "); | 21 | printk("%*c", 1 + spaces, ' '); |
21 | print_ip_sym(ip); | 22 | print_ip_sym(trace->entries[i]); |
22 | } | 23 | } |
23 | } | 24 | } |
25 | EXPORT_SYMBOL_GPL(print_stack_trace); | ||
24 | 26 | ||