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 | } |
