summaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/kernel/stack.c')
-rw-r--r--arch/tile/kernel/stack.c45
1 files changed, 23 insertions, 22 deletions
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index b6268d3..0d54106b 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -30,6 +30,10 @@
#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)
@@ -108,7 +112,6 @@ static bool read_memory_func(void *result, VirtualAddress address,
/* Return a pt_regs pointer for a valid fault handler frame */
static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
{
-#ifndef __tilegx__
const char *fault = NULL; /* happy compiler */
char fault_buf[64];
VirtualAddress sp = kbt->it.sp;
@@ -146,7 +149,6 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
}
if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0)
return p;
-#endif
return NULL;
}
@@ -177,7 +179,7 @@ static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt)
pr_err(" <received signal %d>\n",
frame->info.si_signo);
}
- return &frame->uc.uc_mcontext.regs;
+ return (struct pt_regs *)&frame->uc.uc_mcontext;
}
return NULL;
}
@@ -209,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;
}
}
@@ -266,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;
@@ -292,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();
@@ -307,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);
@@ -351,12 +356,6 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
kbt->task->pid, kbt->task->tgid, kbt->task->comm,
smp_processor_id(), get_cycles());
}
-#ifdef __tilegx__
- if (kbt->is_current) {
- __insn_mtspr(SPR_SIM_CONTROL,
- SIM_DUMP_SPR_ARG(SIM_DUMP_BACKTRACE));
- }
-#endif
kbt->verbose = 1;
i = 0;
for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) {
@@ -395,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");
}
OpenPOWER on IntegriCloud