From 5afe27380bc42454254c9c83c045240249c15e35 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 30 Jul 2008 21:57:59 -0700 Subject: sparc64: Make global reg dumping even more useful. Record one more level of stack frame program counter. Particularly when lockdep and all sorts of spinlock debugging is enabled, figuring out the caller of spin_lock() is difficult when the cpu is stuck on the lock. Signed-off-by: David S. Miller --- arch/sparc64/kernel/process.c | 36 +++++++++++++++++++++++++++++------- arch/sparc64/mm/ultra.S | 7 +++++++ 2 files changed, 36 insertions(+), 7 deletions(-) (limited to 'arch/sparc64') diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 0f60547c24d..fc8137a21ce 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -304,6 +304,19 @@ void show_regs(struct pt_regs *regs) struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; static DEFINE_SPINLOCK(global_reg_snapshot_lock); +static bool kstack_valid(struct thread_info *tp, struct reg_window *rw) +{ + unsigned long thread_base, fp; + + thread_base = (unsigned long) tp; + fp = (unsigned long) rw; + + if (fp < (thread_base + sizeof(struct thread_info)) || + fp >= (thread_base + THREAD_SIZE)) + return false; + return true; +} + static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, int this_cpu) { @@ -315,14 +328,22 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7]; if (regs->tstate & TSTATE_PRIV) { + struct thread_info *tp = current_thread_info(); struct reg_window *rw; rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); - global_reg_snapshot[this_cpu].i7 = rw->ins[7]; - } else + if (kstack_valid(tp, rw)) { + global_reg_snapshot[this_cpu].i7 = rw->ins[7]; + rw = (struct reg_window *) + (rw->ins[6] + STACK_BIAS); + if (kstack_valid(tp, rw)) + global_reg_snapshot[this_cpu].rpc = rw->ins[7]; + } + } else { global_reg_snapshot[this_cpu].i7 = 0; - + global_reg_snapshot[this_cpu].rpc = 0; + } global_reg_snapshot[this_cpu].thread = tp; } @@ -375,13 +396,14 @@ static void sysrq_handle_globreg(int key, struct tty_struct *tty) ((tp && tp->task) ? tp->task->pid : -1)); if (gp->tstate & TSTATE_PRIV) { - printk(" TPC[%pS] O7[%pS] I7[%pS]\n", + printk(" TPC[%pS] O7[%pS] I7[%pS] RPC[%pS]\n", (void *) gp->tpc, (void *) gp->o7, - (void *) gp->i7); + (void *) gp->i7, + (void *) gp->rpc); } else { - printk(" TPC[%lx] O7[%lx] I7[%lx]\n", - gp->tpc, gp->o7, gp->i7); + printk(" TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n", + gp->tpc, gp->o7, gp->i7, gp->rpc); } } diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 4c8ca131ffa..77ba88597cc 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -531,6 +531,13 @@ xcall_fetch_glob_regs: stx %g7, [%g1 + GR_SNAP_TNPC] stx %o7, [%g1 + GR_SNAP_O7] stx %i7, [%g1 + GR_SNAP_I7] + /* Don't try this at home kids... */ + rdpr %cwp, %g2 + sub %g2, 1, %g7 + wrpr %g7, %cwp + mov %i7, %g7 + wrpr %g2, %cwp + stx %g7, [%g1 + GR_SNAP_RPC] sethi %hi(trap_block), %g7 or %g7, %lo(trap_block), %g7 sllx %g2, TRAP_BLOCK_SZ_SHIFT, %g2 -- cgit v1.2.3