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