diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/stacktrace.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index 962944038430..6a4fb003fa54 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c | |||
@@ -10,33 +10,34 @@ | |||
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
13 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
14 | #include <linux/stacktrace.h> | 15 | #include <linux/stacktrace.h> |
15 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
17 | #include <asm/processor.h> | ||
16 | 18 | ||
17 | /* | 19 | /* |
18 | * Save stack-backtrace addresses into a stack_trace buffer. | 20 | * Save stack-backtrace addresses into a stack_trace buffer. |
19 | */ | 21 | */ |
20 | void save_stack_trace(struct stack_trace *trace) | 22 | static void save_context_stack(struct stack_trace *trace, unsigned long sp, |
23 | struct task_struct *tsk, int savesched) | ||
21 | { | 24 | { |
22 | unsigned long sp; | ||
23 | |||
24 | asm("mr %0,1" : "=r" (sp)); | ||
25 | |||
26 | for (;;) { | 25 | for (;;) { |
27 | unsigned long *stack = (unsigned long *) sp; | 26 | unsigned long *stack = (unsigned long *) sp; |
28 | unsigned long newsp, ip; | 27 | unsigned long newsp, ip; |
29 | 28 | ||
30 | if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) | 29 | if (!validate_sp(sp, tsk, STACK_FRAME_OVERHEAD)) |
31 | return; | 30 | return; |
32 | 31 | ||
33 | newsp = stack[0]; | 32 | newsp = stack[0]; |
34 | ip = stack[STACK_FRAME_LR_SAVE]; | 33 | ip = stack[STACK_FRAME_LR_SAVE]; |
35 | 34 | ||
36 | if (!trace->skip) | 35 | if (savesched || !in_sched_functions(ip)) { |
37 | trace->entries[trace->nr_entries++] = ip; | 36 | if (!trace->skip) |
38 | else | 37 | trace->entries[trace->nr_entries++] = ip; |
39 | trace->skip--; | 38 | else |
39 | trace->skip--; | ||
40 | } | ||
40 | 41 | ||
41 | if (trace->nr_entries >= trace->max_entries) | 42 | if (trace->nr_entries >= trace->max_entries) |
42 | return; | 43 | return; |
@@ -44,3 +45,19 @@ void save_stack_trace(struct stack_trace *trace) | |||
44 | sp = newsp; | 45 | sp = newsp; |
45 | } | 46 | } |
46 | } | 47 | } |
48 | |||
49 | void save_stack_trace(struct stack_trace *trace) | ||
50 | { | ||
51 | unsigned long sp; | ||
52 | |||
53 | asm("mr %0,1" : "=r" (sp)); | ||
54 | |||
55 | save_context_stack(trace, sp, current, 1); | ||
56 | } | ||
57 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
58 | |||
59 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
60 | { | ||
61 | save_context_stack(trace, tsk->thread.regs->gpr[1], tsk, 0); | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||