1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2012 ARM Ltd.
4  */
5 #ifndef __ASM_STACKTRACE_H
6 #define __ASM_STACKTRACE_H
7 
8 #include <linux/percpu.h>
9 #include <linux/sched.h>
10 #include <linux/sched/task_stack.h>
11 
12 #include <asm/memory.h>
13 #include <asm/ptrace.h>
14 #include <asm/sdei.h>
15 
16 struct stackframe {
17 	unsigned long fp;
18 	unsigned long pc;
19 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
20 	int graph;
21 #endif
22 };
23 
24 enum stack_type {
25 	STACK_TYPE_UNKNOWN,
26 	STACK_TYPE_TASK,
27 	STACK_TYPE_IRQ,
28 	STACK_TYPE_OVERFLOW,
29 	STACK_TYPE_SDEI_NORMAL,
30 	STACK_TYPE_SDEI_CRITICAL,
31 };
32 
33 struct stack_info {
34 	unsigned long low;
35 	unsigned long high;
36 	enum stack_type type;
37 };
38 
39 extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
40 extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
41 			    int (*fn)(struct stackframe *, void *), void *data);
42 extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk);
43 
44 DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
45 
46 static inline bool on_irq_stack(unsigned long sp,
47 				struct stack_info *info)
48 {
49 	unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
50 	unsigned long high = low + IRQ_STACK_SIZE;
51 
52 	if (!low)
53 		return false;
54 
55 	if (sp < low || sp >= high)
56 		return false;
57 
58 	if (info) {
59 		info->low = low;
60 		info->high = high;
61 		info->type = STACK_TYPE_IRQ;
62 	}
63 
64 	return true;
65 }
66 
67 static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp,
68 				struct stack_info *info)
69 {
70 	unsigned long low = (unsigned long)task_stack_page(tsk);
71 	unsigned long high = low + THREAD_SIZE;
72 
73 	if (sp < low || sp >= high)
74 		return false;
75 
76 	if (info) {
77 		info->low = low;
78 		info->high = high;
79 		info->type = STACK_TYPE_TASK;
80 	}
81 
82 	return true;
83 }
84 
85 #ifdef CONFIG_VMAP_STACK
86 DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
87 
88 static inline bool on_overflow_stack(unsigned long sp,
89 				struct stack_info *info)
90 {
91 	unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
92 	unsigned long high = low + OVERFLOW_STACK_SIZE;
93 
94 	if (sp < low || sp >= high)
95 		return false;
96 
97 	if (info) {
98 		info->low = low;
99 		info->high = high;
100 		info->type = STACK_TYPE_OVERFLOW;
101 	}
102 
103 	return true;
104 }
105 #else
106 static inline bool on_overflow_stack(unsigned long sp,
107 			struct stack_info *info) { return false; }
108 #endif
109 
110 
111 /*
112  * We can only safely access per-cpu stacks from current in a non-preemptible
113  * context.
114  */
115 static inline bool on_accessible_stack(struct task_struct *tsk,
116 					unsigned long sp,
117 					struct stack_info *info)
118 {
119 	if (on_task_stack(tsk, sp, info))
120 		return true;
121 	if (tsk != current || preemptible())
122 		return false;
123 	if (on_irq_stack(sp, info))
124 		return true;
125 	if (on_overflow_stack(sp, info))
126 		return true;
127 	if (on_sdei_stack(sp, info))
128 		return true;
129 
130 	return false;
131 }
132 
133 #endif	/* __ASM_STACKTRACE_H */
134