diff options
-rw-r--r-- | arch/powerpc/kernel/stacktrace.c | 40 |
1 files changed, 14 insertions, 26 deletions
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index 06688f4d557b..28c3c25755d7 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c | |||
@@ -95,20 +95,11 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
95 | struct stack_trace *trace) | 95 | struct stack_trace *trace) |
96 | { | 96 | { |
97 | unsigned long sp; | 97 | unsigned long sp; |
98 | unsigned long newsp; | ||
98 | unsigned long stack_page = (unsigned long)task_stack_page(tsk); | 99 | unsigned long stack_page = (unsigned long)task_stack_page(tsk); |
99 | unsigned long stack_end; | 100 | unsigned long stack_end; |
100 | int graph_idx = 0; | 101 | int graph_idx = 0; |
101 | 102 | bool firstframe; | |
102 | /* | ||
103 | * The last frame (unwinding first) may not yet have saved | ||
104 | * its LR onto the stack. | ||
105 | */ | ||
106 | int firstframe = 1; | ||
107 | |||
108 | if (tsk == current) | ||
109 | sp = current_stack_pointer(); | ||
110 | else | ||
111 | sp = tsk->thread.ksp; | ||
112 | 103 | ||
113 | stack_end = stack_page + THREAD_SIZE; | 104 | stack_end = stack_page + THREAD_SIZE; |
114 | if (!is_idle_task(tsk)) { | 105 | if (!is_idle_task(tsk)) { |
@@ -135,14 +126,20 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
135 | stack_end -= STACK_FRAME_OVERHEAD; | 126 | stack_end -= STACK_FRAME_OVERHEAD; |
136 | } | 127 | } |
137 | 128 | ||
129 | if (tsk == current) | ||
130 | sp = current_stack_pointer(); | ||
131 | else | ||
132 | sp = tsk->thread.ksp; | ||
133 | |||
138 | if (sp < stack_page + sizeof(struct thread_struct) || | 134 | if (sp < stack_page + sizeof(struct thread_struct) || |
139 | sp > stack_end - STACK_FRAME_MIN_SIZE) { | 135 | sp > stack_end - STACK_FRAME_MIN_SIZE) { |
140 | return 1; | 136 | return 1; |
141 | } | 137 | } |
142 | 138 | ||
143 | for (;;) { | 139 | for (firstframe = true; sp != stack_end; |
140 | firstframe = false, sp = newsp) { | ||
144 | unsigned long *stack = (unsigned long *) sp; | 141 | unsigned long *stack = (unsigned long *) sp; |
145 | unsigned long newsp, ip; | 142 | unsigned long ip; |
146 | 143 | ||
147 | /* sanity check: ABI requires SP to be aligned 16 bytes. */ | 144 | /* sanity check: ABI requires SP to be aligned 16 bytes. */ |
148 | if (sp & 0xF) | 145 | if (sp & 0xF) |
@@ -163,10 +160,8 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
163 | * rest of the frame may be uninitialized, continue to | 160 | * rest of the frame may be uninitialized, continue to |
164 | * the next. | 161 | * the next. |
165 | */ | 162 | */ |
166 | if (firstframe) { | 163 | if (firstframe) |
167 | firstframe = 0; | 164 | continue; |
168 | goto next; | ||
169 | } | ||
170 | 165 | ||
171 | /* Mark stacktraces with exception frames as unreliable. */ | 166 | /* Mark stacktraces with exception frames as unreliable. */ |
172 | if (sp <= stack_end - STACK_INT_FRAME_SIZE && | 167 | if (sp <= stack_end - STACK_INT_FRAME_SIZE && |
@@ -193,19 +188,12 @@ save_stack_trace_tsk_reliable(struct task_struct *tsk, | |||
193 | return 1; | 188 | return 1; |
194 | #endif | 189 | #endif |
195 | 190 | ||
191 | if (trace->nr_entries >= trace->max_entries) | ||
192 | return -E2BIG; | ||
196 | if (!trace->skip) | 193 | if (!trace->skip) |
197 | trace->entries[trace->nr_entries++] = ip; | 194 | trace->entries[trace->nr_entries++] = ip; |
198 | else | 195 | else |
199 | trace->skip--; | 196 | trace->skip--; |
200 | |||
201 | next: | ||
202 | if (newsp == stack_end) | ||
203 | break; | ||
204 | |||
205 | if (trace->nr_entries >= trace->max_entries) | ||
206 | return -E2BIG; | ||
207 | |||
208 | sp = newsp; | ||
209 | } | 197 | } |
210 | return 0; | 198 | return 0; |
211 | } | 199 | } |