]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/tile/kernel/stack.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / arch / tile / kernel / stack.c
index ea2e0ce28380a2d3fa59391cfc02cb4ca0022f1e..0d54106be3d66b33f089cc499c0b33d82a3635b6 100644 (file)
 #include <arch/abi.h>
 #include <arch/interrupts.h>
 
+#define KBT_ONGOING    0  /* Backtrace still ongoing */
+#define KBT_DONE       1  /* Backtrace cleanly completed */
+#define KBT_RUNNING    2  /* Can't run backtrace on a running task */
+#define KBT_LOOP       3  /* Backtrace entered a loop */
 
 /* Is address on the specified kernel stack? */
 static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
@@ -207,11 +211,11 @@ static int KBacktraceIterator_next_item_inclusive(
        for (;;) {
                do {
                        if (!KBacktraceIterator_is_sigreturn(kbt))
-                               return 1;
+                               return KBT_ONGOING;
                } while (backtrace_next(&kbt->it));
 
                if (!KBacktraceIterator_restart(kbt))
-                       return 0;
+                       return KBT_DONE;
        }
 }
 
@@ -264,7 +268,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
        kbt->pgtable = NULL;
        kbt->verbose = 0;   /* override in caller if desired */
        kbt->profile = 0;   /* override in caller if desired */
-       kbt->end = 0;
+       kbt->end = KBT_ONGOING;
        kbt->new_context = 0;
        if (is_current) {
                HV_PhysAddr pgdir_pa = hv_inquire_context().page_table;
@@ -290,7 +294,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
        if (regs == NULL) {
                if (is_current || t->state == TASK_RUNNING) {
                        /* Can't do this; we need registers */
-                       kbt->end = 1;
+                       kbt->end = KBT_RUNNING;
                        return;
                }
                pc = get_switch_to_pc();
@@ -305,26 +309,29 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
        }
 
        backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52);
-       kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+       kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
 }
 EXPORT_SYMBOL(KBacktraceIterator_init);
 
 int KBacktraceIterator_end(struct KBacktraceIterator *kbt)
 {
-       return kbt->end;
+       return kbt->end != KBT_ONGOING;
 }
 EXPORT_SYMBOL(KBacktraceIterator_end);
 
 void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
 {
+       VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
        kbt->new_context = 0;
-       if (!backtrace_next(&kbt->it) &&
-           !KBacktraceIterator_restart(kbt)) {
-                       kbt->end = 1;
-                       return;
-               }
-
-       kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+       if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
+               kbt->end = KBT_DONE;
+               return;
+       }
+       kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
+       if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) {
+               /* Trapped in a loop; give up. */
+               kbt->end = KBT_LOOP;
+       }
 }
 EXPORT_SYMBOL(KBacktraceIterator_next);
 
@@ -387,6 +394,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
                        break;
                }
        }
+       if (kbt->end == KBT_LOOP)
+               pr_err("Stack dump stopped; next frame identical to this one\n");
        if (headers)
                pr_err("Stack dump complete\n");
 }