[PATCH 22/23] Make register values available to x86 panic notifiers

From: David VomLehn
Date: Mon Apr 12 2010 - 02:05:29 EST


The save_ptregs() function compiles cleanly for 32-bit and 64-bit
configurations, but has not been tested for either.

Signed-off-by: David VomLehn <dvomlehn@xxxxxxxxx>
---
arch/x86/include/asm/ptrace.h | 115 +++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/traps.c | 6 +-
2 files changed, 118 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 9d369f6..9e2d3d2 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -306,6 +306,121 @@ extern void ptrace_bts_untrace(struct task_struct *tsk);
#define arch_ptrace_untrace(tsk) ptrace_bts_untrace(tsk)
#endif /* CONFIG_X86_PTRACE_BTS */

+#include <linux/ptreg.h>
+#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
+ */
+#ifdef __i386__
+#define PTREG_SAVE(r) " mov %%" #r ", %[" #r "]\n"
+
+static __always_inline
+const struct pt_regs *save_ptregs(register struct pt_regs *regs)
+{
+ __asm__ __volatile__ (
+ PTREG_SAVE(bx)
+ PTREG_SAVE(cx)
+ PTREG_SAVE(dx)
+ PTREG_SAVE(si)
+ PTREG_SAVE(di)
+ PTREG_SAVE(bp)
+ PTREG_SAVE(ax)
+ PTREG_SAVE(ds)
+ PTREG_SAVE(es)
+ PTREG_SAVE(fs)
+ PTREG_SAVE(gs)
+ PTREG_SAVE(cs)
+ PTREG_SAVE(sp)
+ PTREG_SAVE(ss)
+ " pushfl\n"
+ " pop %[flags]\n"
+ "1:\n"
+ " movl $1b, %[ip]\n"
+ :
+ PTREG_OUT(regs, bx, bx),
+ PTREG_OUT(regs, cx, cx),
+ PTREG_OUT(regs, dx, dx),
+ PTREG_OUT(regs, si, si),
+ PTREG_OUT(regs, di, di),
+ PTREG_OUT(regs, bp, bp),
+ PTREG_OUT(regs, ax, ax),
+ PTREG_OUT(regs, ds, ds),
+ PTREG_OUT(regs, es, es),
+ PTREG_OUT(regs, fs, fs),
+ PTREG_OUT(regs, gs, gs),
+ PTREG_OUT(regs, ip, ip),
+ PTREG_OUT(regs, cs, cs),
+ PTREG_OUT(regs, flags, flags),
+ PTREG_OUT(regs, sp, sp),
+ PTREG_OUT(regs, ss, ss)
+ :
+ );
+ return regs;
+}
+#else
+#define PTREG_SAVE(r, name) " movq %%" #r ", %[" #name "]\n"
+#define PTREG_SAVE_R(i) _PTREG_SAVE_I(r, r, i)
+
+#define PTREG_OUT_R(regs, i) _PTREG_OUT_I(regs, r, r, i)
+
+static __always_inline
+const struct pt_regs *save_ptregs(struct pt_regs *regs)
+{
+ __asm__ __volatile__ (
+ PTREG_SAVE_R(15)
+ PTREG_SAVE_R(14)
+ PTREG_SAVE_R(13)
+ PTREG_SAVE_R(12)
+ PTREG_SAVE(rbp, bp)
+ PTREG_SAVE(rbx, bx)
+ PTREG_SAVE_R(11)
+ PTREG_SAVE_R(10)
+ PTREG_SAVE_R(9)
+ PTREG_SAVE_R(8)
+ PTREG_SAVE(rax, ax)
+ PTREG_SAVE(rcx, cx)
+ PTREG_SAVE(rdx, dx)
+ PTREG_SAVE(rsi, si)
+ PTREG_SAVE(rdi, di)
+ "mov %%cs, %%ax\n"
+ PTREG_SAVE(rax, cs)
+ PTREG_SAVE(rsp, sp)
+ "mov %%ss, %%ax\n"
+ PTREG_SAVE(rax, ss)
+ " pushf\n"
+ " popq %[flags]\n"
+ "1:\n"
+ " movq $1b, %[ip]\n"
+ :
+ PTREG_OUT_R(regs, 15),
+ PTREG_OUT_R(regs, 14),
+ PTREG_OUT_R(regs, 13),
+ PTREG_OUT_R(regs, 12),
+ PTREG_OUT(regs, bp, bp),
+ PTREG_OUT(regs, bx, bx),
+ PTREG_OUT_R(regs, 11),
+ PTREG_OUT_R(regs, 10),
+ PTREG_OUT_R(regs, 9),
+ PTREG_OUT_R(regs, 8),
+ PTREG_OUT(regs, ax, ax),
+ PTREG_OUT(regs, cx, cx),
+ PTREG_OUT(regs, dx, dx),
+ PTREG_OUT(regs, si, si),
+ PTREG_OUT(regs, di, di),
+ PTREG_OUT(regs, ip, ip),
+ PTREG_OUT(regs, cs, cs),
+ PTREG_OUT(regs, flags, flags),
+ PTREG_OUT(regs, sp, sp),
+ PTREG_OUT(regs, ss, ss)
+ );
+ return regs;
+}
+#endif /* __i386 */
#endif /* __KERNEL__ */

#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 3339917..5b6af80 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -326,7 +326,7 @@ mem_parity_error(unsigned char reason, struct pt_regs *regs)
#endif

if (panic_on_unrecovered_nmi)
- panic("NMI: Not continuing");
+ panic_with_regs(regs, "NMI: Not continuing");

printk(KERN_EMERG "Dazed and confused, but trying to continue\n");

@@ -344,7 +344,7 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
show_registers(regs);

if (panic_on_io_nmi)
- panic("NMI IOCK error: Not continuing");
+ panic_with_regs(regs, "NMI IOCK error: Not continuing");

/* Re-enable the IOCK line, wait for a few seconds */
reason = (reason & 0xf) | 8;
@@ -380,7 +380,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)

printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
if (panic_on_unrecovered_nmi)
- panic("NMI: Not continuing");
+ panic_with_regs(regs, "NMI: Not continuing");

printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/