From: David VomLehn on
The save_ptregs() function has not been tested or even built. I will need
help to complete this.

Signed-off-by: David VomLehn <dvomlehn(a)cisco.com>
---
arch/sparc/include/asm/ptrace.h | 161 +++++++++++++++++++++++++++++++++++++++
arch/sparc/kernel/traps_32.c | 3 +-
arch/sparc/kernel/traps_64.c | 11 ++-
3 files changed, 169 insertions(+), 6 deletions(-)

diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h
index 30b0b79..7303ebf 100644
--- a/arch/sparc/include/asm/ptrace.h
+++ b/arch/sparc/include/asm/ptrace.h
@@ -420,6 +420,167 @@ extern void show_regs(struct pt_regs *);
#define GR_SNAP_THREAD 0x30
#define GR_SNAP_PAD1 0x38

+/* Macros for saving the contents of registers and for the output constraint
+ * for those registers */
+#include <linux/ptreg.h>
+
+#if defined(__sparc__) && defined(__arch64__)
+#define PTREG_SAVE(r, name) "stx " #r ", %[" #name "]\n"
+#else
+#define PTREG_SAVE(r, name) "st " #r ", %[" #name "]\n"
+#endif
+
+#define PTREG_SAVE_U(i) PTREG_SAVE_IDX(%g, u_regs, i)
+
+#define PTREG_OUT_U(regs, i) PTREG_OUT_IDX(regs, %g, u_regs, i)
+
+#define arch_has_save_ptregs 1
+
+/**
+ * save_ptregs - save processor registers for backtracing
+ * @regs: Pointer to &struct pt_regs structure in which to save the
+ * registers
+ *
+ * Returns a constant pointer to @regs.
+ *
+ * This function must be called first in a function. There must be no
+ * auto variables defined that are initialized before calling this function.
+ */
+#if defined(__sparc__) && defined(__arch64__)
+static __always_inline
+const struct pt_regs *save_ptregs(struct pt_regs *regs)
+{
+ __asm__ __volatile__ (
+ PTREG_SAVE_U(0)
+ PTREG_SAVE_U(1)
+ PTREG_SAVE_U(2)
+ PTREG_SAVE_U(3)
+ PTREG_SAVE_U(4)
+ PTREG_SAVE_U(5)
+ PTREG_SAVE_U(6)
+ PTREG_SAVE_U(7)
+ PTREG_SAVE_U(8)
+ PTREG_SAVE_U(9)
+ PTREG_SAVE_U(10)
+ PTREG_SAVE_U(11)
+ PTREG_SAVE_U(12)
+ PTREG_SAVE_U(13)
+ PTREG_SAVE_U(14)
+ PTREG_SAVE_U(15)
+ PTREG_SAVE(tstate, tstate)
+ PTREG_SAVE(tpc, tpc)
+ PTREG_SAVE(tnpc, tnpc)
+ PTREG_SAVE(y, y)
+ PTREG_SAVE(magic, magic)
+ /*
+ * The current location is the one for which the register
+ * values are correct, even if some had been modified on
+ * function entry. So, the current location is the value to
+ * save as the execution address.
+ */
+ "1:\n"
+ "sethi %%hi(1b), %g7\n"
+ "or %g7, %lo(1b), %g7\n"
+ PTREG_SAVE(%g7, tpc)
+ :
+ PTREG_OUT_U(0),
+ PTREG_OUT_U(1),
+ PTREG_OUT_U(2),
+ PTREG_OUT_U(3),
+ PTREG_OUT_U(4),
+ PTREG_OUT_U(5),
+ PTREG_OUT_U(6),
+ PTREG_OUT_U(7),
+ PTREG_OUT_U(8),
+ PTREG_OUT_U(9),
+ PTREG_OUT_U(10),
+ PTREG_OUT_U(11),
+ PTREG_OUT_U(12),
+ PTREG_OUT_U(13),
+ PTREG_OUT_U(14),
+ PTREG_OUT_U(15),
+ PTREG_OUT(regs, tstate, tstate),
+ PTREG_OUT(regs, tpc, tpc),
+ PTREG_OUT(regs, tnpc, tnpc),
+ PTREG_OUT(regs, y, y),
+ PTREG_OUT(regs, magic, magic)
+ :
+ "g7"
+ );
+
+ return regs;
+}
+#else
+/**
+ * save_ptregs - save processor registers for backtracing
+ * @regs: Pointer to &struct pt_regs structure in which to save the
+ * registers
+ *
+ * Returns a constant pointer to @regs.
+ *
+ * This function must be called first in a function. There must be no
+ * auto variables defined that are initialized before calling this function.
+ */
+static __always_inline
+const struct pt_regs *save_ptregs(struct pt_regs *regs)
+{
+ __asm__ __volatile__ (
+ PTREG_SAVE_U(0)
+ PTREG_SAVE_U(1)
+ PTREG_SAVE_U(2)
+ PTREG_SAVE_U(3)
+ PTREG_SAVE_U(4)
+ PTREG_SAVE_U(5)
+ PTREG_SAVE_U(6)
+ PTREG_SAVE_U(7)
+ PTREG_SAVE_U(8)
+ PTREG_SAVE_U(9)
+ PTREG_SAVE_U(10)
+ PTREG_SAVE_U(11)
+ PTREG_SAVE_U(12)
+ PTREG_SAVE_U(13)
+ PTREG_SAVE_U(14)
+ PTREG_SAVE_U(15)
+ PTREG_SAVE(psr, psr)
+ PTREG_SAVE(pc, pc)
+ PTREG_SAVE(npc, npc)
+ PTREG_SAVE(y, y)
+ PTREG_SAVE(magic, magic)
+ /*
+ * The current location is the one for which the register
+ * values are correct, even if some had been modified on
+ * function entry. So, the current location is the value to
+ * save as the execution address.
+ */
+ :
+ PTREG_OUT_U(0),
+ PTREG_OUT_U(1),
+ PTREG_OUT_U(2),
+ PTREG_OUT_U(3),
+ PTREG_OUT_U(4),
+ PTREG_OUT_U(5),
+ PTREG_OUT_U(6),
+ PTREG_OUT_U(7),
+ PTREG_OUT_U(8),
+ PTREG_OUT_U(9),
+ PTREG_OUT_U(10),
+ PTREG_OUT_U(11),
+ PTREG_OUT_U(12),
+ PTREG_OUT_U(13),
+ PTREG_OUT_U(14),
+ PTREG_OUT_U(15),
+ PTREG_OUT(regs, psr, psr),
+ PTREG_OUT(regs, pc, pc),
+ PTREG_OUT(regs, npc, npc),
+ PTREG_OUT(regs, y, y),
+ PTREG_OUT(regs, magic, magic)
+ :
+ );
+
+ return regs;
+}
+#endif /* (defined(__sparc__) && defined(__arch64__)) */
+
#endif /* __KERNEL__ */

/* Stuff for the ptrace system call */
diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c
index c0490c7..9b41e2f 100644
--- a/arch/sparc/kernel/traps_32.c
+++ b/arch/sparc/kernel/traps_32.c
@@ -353,7 +353,8 @@ void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc
pc, npc, psr);
#endif
if(psr & PSR_PS)
- panic("Tell me what a watchpoint trap is, and I'll then deal "
+ panic_with_regs(regs,
+ "Tell me what a watchpoint trap is, and I'll then deal "
"with such a beast...");
}

diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index 10f7bb9..c4035d3 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -1347,7 +1347,7 @@ void cheetah_fecc_handler(struct pt_regs *regs, unsigned long afsr, unsigned lon
cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);

if (!recoverable)
- panic("Irrecoverable Fast-ECC error trap.\n");
+ panic_with_regs(regs, "Irrecoverable Fast-ECC error trap.\n");

/* Flush E-cache to kick the error trap handlers out. */
cheetah_flush_ecache();
@@ -1525,7 +1525,8 @@ void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long
cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);

if (!recoverable)
- panic("Irrecoverable Correctable-ECC error trap.\n");
+ panic_with_regs(regs,
+ "Irrecoverable Correctable-ECC error trap.\n");
}

void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
@@ -1712,7 +1713,7 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned
}

if (!recoverable)
- panic("Irrecoverable deferred error trap.\n");
+ panic_with_regs(regs, "Irrecoverable deferred error trap.\n");
}

/* Handle a D/I cache parity error trap. TYPE is encoded as:
@@ -1747,7 +1748,7 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs)
(type & 0x1) ? 'I' : 'D',
regs->tpc);
printk(KERN_EMERG "TPC<%pS>\n", (void *) regs->tpc);
- panic("Irrecoverable Cheetah+ parity error.");
+ panic_with_regs(regs, "Irrecoverable Cheetah+ parity error.");
}

printk(KERN_WARNING "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
@@ -1934,7 +1935,7 @@ void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
KERN_EMERG "NON-RESUMABLE ERROR",
&sun4v_nonresum_oflow_cnt);

- panic("Non-resumable error.");
+ panic_with_regs(regs, "Non-resumable error.");
}

/* If we try to printk() we'll probably make matters worse, by trying
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/