diff options
-rw-r--r-- | arch/arm/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/avr32/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/mips/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/stacktrace.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/stacktrace.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/stacktrace.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/stacktrace.c | 2 | ||||
-rw-r--r-- | kernel/backtracetest.c | 65 | ||||
-rw-r--r-- | kernel/stacktrace.c | 14 | ||||
-rw-r--r-- | lib/Kconfig.debug | 4 |
11 files changed, 77 insertions, 18 deletions
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 90e0c35ae60d..fc650f64df43 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c | |||
@@ -92,4 +92,5 @@ void save_stack_trace(struct stack_trace *trace) | |||
92 | { | 92 | { |
93 | save_stack_trace_tsk(current, trace); | 93 | save_stack_trace_tsk(current, trace); |
94 | } | 94 | } |
95 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
95 | #endif | 96 | #endif |
diff --git a/arch/avr32/kernel/stacktrace.c b/arch/avr32/kernel/stacktrace.c index 9a68190bbffd..f4bdb448049c 100644 --- a/arch/avr32/kernel/stacktrace.c +++ b/arch/avr32/kernel/stacktrace.c | |||
@@ -51,3 +51,4 @@ void save_stack_trace(struct stack_trace *trace) | |||
51 | fp = frame->fp; | 51 | fp = frame->fp; |
52 | } | 52 | } |
53 | } | 53 | } |
54 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index ebd9db8d1ece..5eb4681a73d2 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c | |||
@@ -73,3 +73,4 @@ void save_stack_trace(struct stack_trace *trace) | |||
73 | prepare_frametrace(regs); | 73 | prepare_frametrace(regs); |
74 | save_context_stack(trace, regs); | 74 | save_context_stack(trace, regs); |
75 | } | 75 | } |
76 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index 962944038430..3cf0d94ba340 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/stacktrace.h> | 14 | #include <linux/stacktrace.h> |
15 | #include <linux/module.h> | ||
15 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
16 | 17 | ||
17 | /* | 18 | /* |
@@ -44,3 +45,4 @@ void save_stack_trace(struct stack_trace *trace) | |||
44 | sp = newsp; | 45 | sp = newsp; |
45 | } | 46 | } |
46 | } | 47 | } |
48 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 85e46a5d0e08..57571f10270c 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c | |||
@@ -81,6 +81,7 @@ void save_stack_trace(struct stack_trace *trace) | |||
81 | S390_lowcore.thread_info, | 81 | S390_lowcore.thread_info, |
82 | S390_lowcore.thread_info + THREAD_SIZE, 1); | 82 | S390_lowcore.thread_info + THREAD_SIZE, 1); |
83 | } | 83 | } |
84 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
84 | 85 | ||
85 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 86 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
86 | { | 87 | { |
@@ -93,3 +94,4 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |||
93 | if (trace->nr_entries < trace->max_entries) | 94 | if (trace->nr_entries < trace->max_entries) |
94 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 95 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
95 | } | 96 | } |
97 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c index d41e561be20e..1b2ae35c4a76 100644 --- a/arch/sh/kernel/stacktrace.c +++ b/arch/sh/kernel/stacktrace.c | |||
@@ -34,3 +34,4 @@ void save_stack_trace(struct stack_trace *trace) | |||
34 | } | 34 | } |
35 | } | 35 | } |
36 | } | 36 | } |
37 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c index c73ce3f4197e..b3e3737750d8 100644 --- a/arch/sparc64/kernel/stacktrace.c +++ b/arch/sparc64/kernel/stacktrace.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <linux/sched.h> | 1 | #include <linux/sched.h> |
2 | #include <linux/stacktrace.h> | 2 | #include <linux/stacktrace.h> |
3 | #include <linux/thread_info.h> | 3 | #include <linux/thread_info.h> |
4 | #include <linux/module.h> | ||
4 | #include <asm/ptrace.h> | 5 | #include <asm/ptrace.h> |
5 | #include <asm/stacktrace.h> | 6 | #include <asm/stacktrace.h> |
6 | 7 | ||
@@ -47,3 +48,4 @@ void save_stack_trace(struct stack_trace *trace) | |||
47 | trace->entries[trace->nr_entries++] = pc; | 48 | trace->entries[trace->nr_entries++] = pc; |
48 | } while (trace->nr_entries < trace->max_entries); | 49 | } while (trace->nr_entries < trace->max_entries); |
49 | } | 50 | } |
51 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index c28c342c162f..a03e7f6d90c3 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
@@ -74,6 +74,7 @@ void save_stack_trace(struct stack_trace *trace) | |||
74 | if (trace->nr_entries < trace->max_entries) | 74 | if (trace->nr_entries < trace->max_entries) |
75 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 75 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
76 | } | 76 | } |
77 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
77 | 78 | ||
78 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 79 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
79 | { | 80 | { |
@@ -81,3 +82,4 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |||
81 | if (trace->nr_entries < trace->max_entries) | 82 | if (trace->nr_entries < trace->max_entries) |
82 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 83 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
83 | } | 84 | } |
85 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||
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 | ||
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d8b6279a9b42..c459e8547bd8 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -419,7 +419,6 @@ config DEBUG_LOCKING_API_SELFTESTS | |||
419 | 419 | ||
420 | config STACKTRACE | 420 | config STACKTRACE |
421 | bool | 421 | bool |
422 | depends on DEBUG_KERNEL | ||
423 | depends on STACKTRACE_SUPPORT | 422 | depends on STACKTRACE_SUPPORT |
424 | 423 | ||
425 | config DEBUG_KOBJECT | 424 | config DEBUG_KOBJECT |
@@ -563,6 +562,9 @@ config BACKTRACE_SELF_TEST | |||
563 | for distributions or general kernels, but only for kernel | 562 | for distributions or general kernels, but only for kernel |
564 | developers working on architecture code. | 563 | developers working on architecture code. |
565 | 564 | ||
565 | Note that if you want to also test saved backtraces, you will | ||
566 | have to enable STACKTRACE as well. | ||
567 | |||
566 | Say N if you are unsure. | 568 | Say N if you are unsure. |
567 | 569 | ||
568 | config LKDTM | 570 | config LKDTM |