1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_STACKTRACE_H
3#define _ASM_STACKTRACE_H
4
5#include <asm/ptrace.h>
6#include <asm/asm.h>
7#include <linux/stringify.h>
8
9#ifdef CONFIG_KALLSYMS
10extern int raw_show_trace;
11extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
12				  unsigned long pc, unsigned long *ra);
13extern unsigned long unwind_stack_by_address(unsigned long stack_page,
14					     unsigned long *sp,
15					     unsigned long pc,
16					     unsigned long *ra);
17#else
18#define raw_show_trace 1
19static inline unsigned long unwind_stack(struct task_struct *task,
20	unsigned long *sp, unsigned long pc, unsigned long *ra)
21{
22	return 0;
23}
24#endif
25
26#define STR_PTR_LA    __stringify(PTR_LA)
27#define STR_LONG_S    __stringify(LONG_S)
28#define STR_LONG_L    __stringify(LONG_L)
29#define STR_LONGSIZE  __stringify(LONGSIZE)
30
31#define STORE_ONE_REG(r) \
32    STR_LONG_S   " $" __stringify(r)",("STR_LONGSIZE"*"__stringify(r)")(%1)\n\t"
33
34static __always_inline void prepare_frametrace(struct pt_regs *regs)
35{
36#ifndef CONFIG_KALLSYMS
37	/*
38	 * Remove any garbage that may be in regs (specially func
39	 * addresses) to avoid show_raw_backtrace() to report them
40	 */
41	memset(regs, 0, sizeof(*regs));
42#endif
43	__asm__ __volatile__(
44		".set push\n\t"
45		".set noat\n\t"
46		/* Store $1 so we can use it */
47		STR_LONG_S " $1,"STR_LONGSIZE"(%1)\n\t"
48		/* Store the PC */
49		"1: " STR_PTR_LA " $1, 1b\n\t"
50		STR_LONG_S " $1,%0\n\t"
51		STORE_ONE_REG(2)
52		STORE_ONE_REG(3)
53		STORE_ONE_REG(4)
54		STORE_ONE_REG(5)
55		STORE_ONE_REG(6)
56		STORE_ONE_REG(7)
57		STORE_ONE_REG(8)
58		STORE_ONE_REG(9)
59		STORE_ONE_REG(10)
60		STORE_ONE_REG(11)
61		STORE_ONE_REG(12)
62		STORE_ONE_REG(13)
63		STORE_ONE_REG(14)
64		STORE_ONE_REG(15)
65		STORE_ONE_REG(16)
66		STORE_ONE_REG(17)
67		STORE_ONE_REG(18)
68		STORE_ONE_REG(19)
69		STORE_ONE_REG(20)
70		STORE_ONE_REG(21)
71		STORE_ONE_REG(22)
72		STORE_ONE_REG(23)
73		STORE_ONE_REG(24)
74		STORE_ONE_REG(25)
75		STORE_ONE_REG(26)
76		STORE_ONE_REG(27)
77		STORE_ONE_REG(28)
78		STORE_ONE_REG(29)
79		STORE_ONE_REG(30)
80		STORE_ONE_REG(31)
81		/* Restore $1 */
82		STR_LONG_L " $1,"STR_LONGSIZE"(%1)\n\t"
83		".set pop\n\t"
84		: "=m" (regs->cp0_epc)
85		: "r" (regs->regs)
86		: "memory");
87}
88
89#endif /* _ASM_STACKTRACE_H */
90