summaryrefslogtreecommitdiffstats
path: root/arch/mips/include
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2017-08-10 13:27:40 -0500
committerRalf Baechle <ralf@linux-mips.org>2017-09-06 11:02:11 +0200
commit5b6b084728f78dadcdba7e48ecb88bc4dbfaa81a (patch)
tree2546694e4d579c68a0c88a67ad240bce156553d9 /arch/mips/include
parent866b6a89c6d1876fce25c152ef9f887b41ffcf7f (diff)
downloadlinux-5b6b084728f78dadcdba7e48ecb88bc4dbfaa81a.tar.bz2
mips: Save all registers when saving the frame
The MIPS frame save code was just saving a few registers, enough to do a backtrace if every function set up a frame. However, this is not working if you are using DWARF unwinding, because most of the registers are wrong. This was causing kdump backtraces to be short or bogus. So save all the registers. Signed-off-by: Corey Minyard <cminyard@mvista.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/16989/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/include')
-rw-r--r--arch/mips/include/asm/stacktrace.h64
1 files changed, 50 insertions, 14 deletions
diff --git a/arch/mips/include/asm/stacktrace.h b/arch/mips/include/asm/stacktrace.h
index 780ee2c2a2ac..10c4e9c84448 100644
--- a/arch/mips/include/asm/stacktrace.h
+++ b/arch/mips/include/asm/stacktrace.h
@@ -2,6 +2,8 @@
#define _ASM_STACKTRACE_H
#include <asm/ptrace.h>
+#include <asm/asm.h>
+#include <linux/stringify.h>
#ifdef CONFIG_KALLSYMS
extern int raw_show_trace;
@@ -20,6 +22,14 @@ static inline unsigned long unwind_stack(struct task_struct *task,
}
#endif
+#define STR_PTR_LA __stringify(PTR_LA)
+#define STR_LONG_S __stringify(LONG_S)
+#define STR_LONG_L __stringify(LONG_L)
+#define STR_LONGSIZE __stringify(LONGSIZE)
+
+#define STORE_ONE_REG(r) \
+ STR_LONG_S " $" __stringify(r)",("STR_LONGSIZE"*"__stringify(r)")(%1)\n\t"
+
static __always_inline void prepare_frametrace(struct pt_regs *regs)
{
#ifndef CONFIG_KALLSYMS
@@ -32,21 +42,47 @@ static __always_inline void prepare_frametrace(struct pt_regs *regs)
__asm__ __volatile__(
".set push\n\t"
".set noat\n\t"
-#ifdef CONFIG_64BIT
- "1: dla $1, 1b\n\t"
- "sd $1, %0\n\t"
- "sd $29, %1\n\t"
- "sd $31, %2\n\t"
-#else
- "1: la $1, 1b\n\t"
- "sw $1, %0\n\t"
- "sw $29, %1\n\t"
- "sw $31, %2\n\t"
-#endif
+ /* Store $1 so we can use it */
+ STR_LONG_S " $1,"STR_LONGSIZE"(%1)\n\t"
+ /* Store the PC */
+ "1: " STR_PTR_LA " $1, 1b\n\t"
+ STR_LONG_S " $1,%0\n\t"
+ STORE_ONE_REG(2)
+ STORE_ONE_REG(3)
+ STORE_ONE_REG(4)
+ STORE_ONE_REG(5)
+ STORE_ONE_REG(6)
+ STORE_ONE_REG(7)
+ STORE_ONE_REG(8)
+ STORE_ONE_REG(9)
+ STORE_ONE_REG(10)
+ STORE_ONE_REG(11)
+ STORE_ONE_REG(12)
+ STORE_ONE_REG(13)
+ STORE_ONE_REG(14)
+ STORE_ONE_REG(15)
+ STORE_ONE_REG(16)
+ STORE_ONE_REG(17)
+ STORE_ONE_REG(18)
+ STORE_ONE_REG(19)
+ STORE_ONE_REG(20)
+ STORE_ONE_REG(21)
+ STORE_ONE_REG(22)
+ STORE_ONE_REG(23)
+ STORE_ONE_REG(24)
+ STORE_ONE_REG(25)
+ STORE_ONE_REG(26)
+ STORE_ONE_REG(27)
+ STORE_ONE_REG(28)
+ STORE_ONE_REG(29)
+ STORE_ONE_REG(30)
+ STORE_ONE_REG(31)
+ /* Restore $1 */
+ STR_LONG_L " $1,"STR_LONGSIZE"(%1)\n\t"
".set pop\n\t"
- : "=m" (regs->cp0_epc),
- "=m" (regs->regs[29]), "=m" (regs->regs[31])
- : : "memory");
+ : "=m" (regs->cp0_epc)
+ : "r" (regs->regs)
+ : "memory");
}
#endif /* _ASM_STACKTRACE_H */