diff options
-rw-r--r-- | arch/avr32/Kconfig | 3 | ||||
-rw-r--r-- | arch/avr32/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/avr32/kernel/stacktrace.c | 53 |
3 files changed, 57 insertions, 0 deletions
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index b108dd83f234..599ec166d833 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig | |||
@@ -24,6 +24,9 @@ config GENERIC_GPIO | |||
24 | config GENERIC_HARDIRQS | 24 | config GENERIC_HARDIRQS |
25 | def_bool y | 25 | def_bool y |
26 | 26 | ||
27 | config STACKTRACE_SUPPORT | ||
28 | def_bool y | ||
29 | |||
27 | config HARDIRQS_SW_RESEND | 30 | config HARDIRQS_SW_RESEND |
28 | def_bool y | 31 | def_bool y |
29 | 32 | ||
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 989fcd1fef7e..2d6d48f35f69 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile | |||
@@ -11,3 +11,4 @@ obj-y += signal.o sys_avr32.o process.o time.o | |||
11 | obj-y += init_task.o switch_to.o cpu.o | 11 | obj-y += init_task.o switch_to.o cpu.o |
12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o | 12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o |
13 | obj-$(CONFIG_KPROBES) += kprobes.o | 13 | obj-$(CONFIG_KPROBES) += kprobes.o |
14 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | ||
diff --git a/arch/avr32/kernel/stacktrace.c b/arch/avr32/kernel/stacktrace.c new file mode 100644 index 000000000000..9a68190bbffd --- /dev/null +++ b/arch/avr32/kernel/stacktrace.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Stack trace management functions | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/stacktrace.h> | ||
12 | #include <linux/thread_info.h> | ||
13 | |||
14 | register unsigned long current_frame_pointer asm("r7"); | ||
15 | |||
16 | struct stackframe { | ||
17 | unsigned long lr; | ||
18 | unsigned long fp; | ||
19 | }; | ||
20 | |||
21 | /* | ||
22 | * Save stack-backtrace addresses into a stack_trace buffer. | ||
23 | */ | ||
24 | void save_stack_trace(struct stack_trace *trace) | ||
25 | { | ||
26 | unsigned long low, high; | ||
27 | unsigned long fp; | ||
28 | struct stackframe *frame; | ||
29 | int skip = trace->skip; | ||
30 | |||
31 | low = (unsigned long)task_stack_page(current); | ||
32 | high = low + THREAD_SIZE; | ||
33 | fp = current_frame_pointer; | ||
34 | |||
35 | while (fp >= low && fp <= (high - 8)) { | ||
36 | frame = (struct stackframe *)fp; | ||
37 | |||
38 | if (skip) { | ||
39 | skip--; | ||
40 | } else { | ||
41 | trace->entries[trace->nr_entries++] = frame->lr; | ||
42 | if (trace->nr_entries >= trace->max_entries) | ||
43 | break; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * The next frame must be at a higher address than the | ||
48 | * current frame. | ||
49 | */ | ||
50 | low = fp + 8; | ||
51 | fp = frame->fp; | ||
52 | } | ||
53 | } | ||