diff options
Diffstat (limited to 'arch/tile/kernel/stack.c')
-rw-r--r-- | arch/tile/kernel/stack.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index ea2e0ce28380..0d54106be3d6 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c | |||
@@ -30,6 +30,10 @@ | |||
30 | #include <arch/abi.h> | 30 | #include <arch/abi.h> |
31 | #include <arch/interrupts.h> | 31 | #include <arch/interrupts.h> |
32 | 32 | ||
33 | #define KBT_ONGOING 0 /* Backtrace still ongoing */ | ||
34 | #define KBT_DONE 1 /* Backtrace cleanly completed */ | ||
35 | #define KBT_RUNNING 2 /* Can't run backtrace on a running task */ | ||
36 | #define KBT_LOOP 3 /* Backtrace entered a loop */ | ||
33 | 37 | ||
34 | /* Is address on the specified kernel stack? */ | 38 | /* Is address on the specified kernel stack? */ |
35 | static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp) | 39 | static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp) |
@@ -207,11 +211,11 @@ static int KBacktraceIterator_next_item_inclusive( | |||
207 | for (;;) { | 211 | for (;;) { |
208 | do { | 212 | do { |
209 | if (!KBacktraceIterator_is_sigreturn(kbt)) | 213 | if (!KBacktraceIterator_is_sigreturn(kbt)) |
210 | return 1; | 214 | return KBT_ONGOING; |
211 | } while (backtrace_next(&kbt->it)); | 215 | } while (backtrace_next(&kbt->it)); |
212 | 216 | ||
213 | if (!KBacktraceIterator_restart(kbt)) | 217 | if (!KBacktraceIterator_restart(kbt)) |
214 | return 0; | 218 | return KBT_DONE; |
215 | } | 219 | } |
216 | } | 220 | } |
217 | 221 | ||
@@ -264,7 +268,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt, | |||
264 | kbt->pgtable = NULL; | 268 | kbt->pgtable = NULL; |
265 | kbt->verbose = 0; /* override in caller if desired */ | 269 | kbt->verbose = 0; /* override in caller if desired */ |
266 | kbt->profile = 0; /* override in caller if desired */ | 270 | kbt->profile = 0; /* override in caller if desired */ |
267 | kbt->end = 0; | 271 | kbt->end = KBT_ONGOING; |
268 | kbt->new_context = 0; | 272 | kbt->new_context = 0; |
269 | if (is_current) { | 273 | if (is_current) { |
270 | HV_PhysAddr pgdir_pa = hv_inquire_context().page_table; | 274 | HV_PhysAddr pgdir_pa = hv_inquire_context().page_table; |
@@ -290,7 +294,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt, | |||
290 | if (regs == NULL) { | 294 | if (regs == NULL) { |
291 | if (is_current || t->state == TASK_RUNNING) { | 295 | if (is_current || t->state == TASK_RUNNING) { |
292 | /* Can't do this; we need registers */ | 296 | /* Can't do this; we need registers */ |
293 | kbt->end = 1; | 297 | kbt->end = KBT_RUNNING; |
294 | return; | 298 | return; |
295 | } | 299 | } |
296 | pc = get_switch_to_pc(); | 300 | pc = get_switch_to_pc(); |
@@ -305,26 +309,29 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt, | |||
305 | } | 309 | } |
306 | 310 | ||
307 | backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52); | 311 | backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52); |
308 | kbt->end = !KBacktraceIterator_next_item_inclusive(kbt); | 312 | kbt->end = KBacktraceIterator_next_item_inclusive(kbt); |
309 | } | 313 | } |
310 | EXPORT_SYMBOL(KBacktraceIterator_init); | 314 | EXPORT_SYMBOL(KBacktraceIterator_init); |
311 | 315 | ||
312 | int KBacktraceIterator_end(struct KBacktraceIterator *kbt) | 316 | int KBacktraceIterator_end(struct KBacktraceIterator *kbt) |
313 | { | 317 | { |
314 | return kbt->end; | 318 | return kbt->end != KBT_ONGOING; |
315 | } | 319 | } |
316 | EXPORT_SYMBOL(KBacktraceIterator_end); | 320 | EXPORT_SYMBOL(KBacktraceIterator_end); |
317 | 321 | ||
318 | void KBacktraceIterator_next(struct KBacktraceIterator *kbt) | 322 | void KBacktraceIterator_next(struct KBacktraceIterator *kbt) |
319 | { | 323 | { |
324 | VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp; | ||
320 | kbt->new_context = 0; | 325 | kbt->new_context = 0; |
321 | if (!backtrace_next(&kbt->it) && | 326 | if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) { |
322 | !KBacktraceIterator_restart(kbt)) { | 327 | kbt->end = KBT_DONE; |
323 | kbt->end = 1; | 328 | return; |
324 | return; | 329 | } |
325 | } | 330 | kbt->end = KBacktraceIterator_next_item_inclusive(kbt); |
326 | 331 | if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) { | |
327 | kbt->end = !KBacktraceIterator_next_item_inclusive(kbt); | 332 | /* Trapped in a loop; give up. */ |
333 | kbt->end = KBT_LOOP; | ||
334 | } | ||
328 | } | 335 | } |
329 | EXPORT_SYMBOL(KBacktraceIterator_next); | 336 | EXPORT_SYMBOL(KBacktraceIterator_next); |
330 | 337 | ||
@@ -387,6 +394,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers) | |||
387 | break; | 394 | break; |
388 | } | 395 | } |
389 | } | 396 | } |
397 | if (kbt->end == KBT_LOOP) | ||
398 | pr_err("Stack dump stopped; next frame identical to this one\n"); | ||
390 | if (headers) | 399 | if (headers) |
391 | pr_err("Stack dump complete\n"); | 400 | pr_err("Stack dump complete\n"); |
392 | } | 401 | } |