1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Common arm64 stack unwinder code.
4 *
5 * See: arch/arm64/kernel/stacktrace.c for the reference implementation.
6 *
7 * Copyright (C) 2012 ARM Ltd.
8 */
9 #ifndef __ASM_STACKTRACE_COMMON_H
10 #define __ASM_STACKTRACE_COMMON_H
11
12 #include <linux/types.h>
13
14 struct stack_info {
15 unsigned long low;
16 unsigned long high;
17 };
18
19 /**
20 * struct unwind_state - state used for robust unwinding.
21 *
22 * @fp: The fp value in the frame record (or the real fp)
23 * @pc: The lr value in the frame record (or the real lr)
24 *
25 * @stack: The stack currently being unwound.
26 * @stacks: An array of stacks which can be unwound.
27 * @nr_stacks: The number of stacks in @stacks.
28 */
29 struct unwind_state {
30 unsigned long fp;
31 unsigned long pc;
32
33 struct stack_info stack;
34 struct stack_info *stacks;
35 int nr_stacks;
36 };
37
stackinfo_get_unknown(void)38 static inline struct stack_info stackinfo_get_unknown(void)
39 {
40 return (struct stack_info) {
41 .low = 0,
42 .high = 0,
43 };
44 }
45
stackinfo_on_stack(const struct stack_info * info,unsigned long sp,unsigned long size)46 static inline bool stackinfo_on_stack(const struct stack_info *info,
47 unsigned long sp, unsigned long size)
48 {
49 if (!info->low)
50 return false;
51
52 if (sp < info->low || sp + size < sp || sp + size > info->high)
53 return false;
54
55 return true;
56 }
57
unwind_init_common(struct unwind_state * state)58 static inline void unwind_init_common(struct unwind_state *state)
59 {
60 state->stack = stackinfo_get_unknown();
61 }
62
63 /**
64 * unwind_find_stack() - Find the accessible stack which entirely contains an
65 * object.
66 *
67 * @state: the current unwind state.
68 * @sp: the base address of the object.
69 * @size: the size of the object.
70 *
71 * Return: a pointer to the relevant stack_info if found; NULL otherwise.
72 */
unwind_find_stack(struct unwind_state * state,unsigned long sp,unsigned long size)73 static struct stack_info *unwind_find_stack(struct unwind_state *state,
74 unsigned long sp,
75 unsigned long size)
76 {
77 struct stack_info *info = &state->stack;
78
79 if (stackinfo_on_stack(info, sp, size))
80 return info;
81
82 for (int i = 0; i < state->nr_stacks; i++) {
83 info = &state->stacks[i];
84 if (stackinfo_on_stack(info, sp, size))
85 return info;
86 }
87
88 return NULL;
89 }
90
91 /**
92 * unwind_consume_stack() - Update stack boundaries so that future unwind steps
93 * cannot consume this object again.
94 *
95 * @state: the current unwind state.
96 * @info: the stack_info of the stack containing the object.
97 * @sp: the base address of the object.
98 * @size: the size of the object.
99 *
100 * Return: 0 upon success, an error code otherwise.
101 */
unwind_consume_stack(struct unwind_state * state,struct stack_info * info,unsigned long sp,unsigned long size)102 static inline void unwind_consume_stack(struct unwind_state *state,
103 struct stack_info *info,
104 unsigned long sp,
105 unsigned long size)
106 {
107 struct stack_info tmp;
108
109 /*
110 * Stack transitions are strictly one-way, and once we've
111 * transitioned from one stack to another, it's never valid to
112 * unwind back to the old stack.
113 *
114 * Destroy the old stack info so that it cannot be found upon a
115 * subsequent transition. If the stack has not changed, we'll
116 * immediately restore the current stack info.
117 *
118 * Note that stacks can nest in several valid orders, e.g.
119 *
120 * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL
121 * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW
122 * HYP -> OVERFLOW
123 *
124 * ... so we do not check the specific order of stack
125 * transitions.
126 */
127 tmp = *info;
128 *info = stackinfo_get_unknown();
129 state->stack = tmp;
130
131 /*
132 * Future unwind steps can only consume stack above this frame record.
133 * Update the current stack to start immediately above it.
134 */
135 state->stack.low = sp + size;
136 }
137
138 /**
139 * unwind_next_frame_record() - Unwind to the next frame record.
140 *
141 * @state: the current unwind state.
142 *
143 * Return: 0 upon success, an error code otherwise.
144 */
145 static inline int
unwind_next_frame_record(struct unwind_state * state)146 unwind_next_frame_record(struct unwind_state *state)
147 {
148 struct stack_info *info;
149 struct frame_record *record;
150 unsigned long fp = state->fp;
151
152 if (fp & 0x7)
153 return -EINVAL;
154
155 info = unwind_find_stack(state, fp, sizeof(*record));
156 if (!info)
157 return -EINVAL;
158
159 unwind_consume_stack(state, info, fp, sizeof(*record));
160
161 /*
162 * Record this frame record's values.
163 */
164 record = (struct frame_record *)fp;
165 state->fp = READ_ONCE(record->fp);
166 state->pc = READ_ONCE(record->lr);
167
168 return 0;
169 }
170
171 #endif /* __ASM_STACKTRACE_COMMON_H */
172