summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sparc/include/asm/ptrace_64.h8
-rw-r--r--arch/sparc64/kernel/process.c36
-rw-r--r--arch/sparc64/mm/ultra.S7
3 files changed, 40 insertions, 11 deletions
diff --git a/arch/sparc/include/asm/ptrace_64.h b/arch/sparc/include/asm/ptrace_64.h
index ec6d45c84cd0..390d92ac67cf 100644
--- a/arch/sparc/include/asm/ptrace_64.h
+++ b/arch/sparc/include/asm/ptrace_64.h
@@ -134,9 +134,9 @@ struct global_reg_snapshot {
unsigned long tnpc;
unsigned long o7;
unsigned long i7;
+ unsigned long rpc;
struct thread_info *thread;
unsigned long pad1;
- unsigned long pad2;
};
#define __ARCH_WANT_COMPAT_SYS_PTRACE
@@ -315,9 +315,9 @@ extern void __show_regs(struct pt_regs *);
#define GR_SNAP_TNPC 0x10
#define GR_SNAP_O7 0x18
#define GR_SNAP_I7 0x20
-#define GR_SNAP_THREAD 0x28
-#define GR_SNAP_PAD1 0x30
-#define GR_SNAP_PAD2 0x38
+#define GR_SNAP_RPC 0x28
+#define GR_SNAP_THREAD 0x30
+#define GR_SNAP_PAD1 0x38
#endif /* __KERNEL__ */
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 0f60547c24d9..fc8137a21ced 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 4c8ca131ffaf..77ba88597cc5 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