diff options
Diffstat (limited to 'arch/blackfin/kernel/stacktrace.c')
-rw-r--r-- | arch/blackfin/kernel/stacktrace.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/stacktrace.c b/arch/blackfin/kernel/stacktrace.c new file mode 100644 index 000000000000..30301e1eace5 --- /dev/null +++ b/arch/blackfin/kernel/stacktrace.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Blackfin stacktrace code (mostly copied from avr32) | ||
3 | * | ||
4 | * Copyright 2009 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #include <linux/sched.h> | ||
9 | #include <linux/stacktrace.h> | ||
10 | #include <linux/thread_info.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | register unsigned long current_frame_pointer asm("FP"); | ||
14 | |||
15 | struct stackframe { | ||
16 | unsigned long fp; | ||
17 | unsigned long rets; | ||
18 | }; | ||
19 | |||
20 | /* | ||
21 | * Save stack-backtrace addresses into a stack_trace buffer. | ||
22 | */ | ||
23 | void save_stack_trace(struct stack_trace *trace) | ||
24 | { | ||
25 | unsigned long low, high; | ||
26 | unsigned long fp; | ||
27 | struct stackframe *frame; | ||
28 | int skip = trace->skip; | ||
29 | |||
30 | low = (unsigned long)task_stack_page(current); | ||
31 | high = low + THREAD_SIZE; | ||
32 | fp = current_frame_pointer; | ||
33 | |||
34 | while (fp >= low && fp <= (high - sizeof(*frame))) { | ||
35 | frame = (struct stackframe *)fp; | ||
36 | |||
37 | if (skip) { | ||
38 | skip--; | ||
39 | } else { | ||
40 | trace->entries[trace->nr_entries++] = frame->rets; | ||
41 | if (trace->nr_entries >= trace->max_entries) | ||
42 | break; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * The next frame must be at a higher address than the | ||
47 | * current frame. | ||
48 | */ | ||
49 | low = fp + sizeof(*frame); | ||
50 | fp = frame->fp; | ||
51 | } | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||