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/kprobes.h>
13 #include <linux/types.h>
14
15 struct stack_info {
16 unsigned long low;
17 unsigned long high;
18 };
19
20 /**
21 * struct unwind_state - state used for robust unwinding.
22 *
23 * @fp: The fp value in the frame record (or the real fp)
24 * @pc: The lr value in the frame record (or the real lr)
25 *
26 * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance
27 * associated with the most recently encountered replacement lr
28 * value.
29 *
30 * @task: The task being unwound.
31 *
32 * @stack: The stack currently being unwound.
33 * @stacks: An array of stacks which can be unwound.
34 * @nr_stacks: The number of stacks in @stacks.
35 */
36 struct unwind_state {
37 unsigned long fp;
38 unsigned long pc;
39 #ifdef CONFIG_KRETPROBES
40 struct llist_node *kr_cur;
41 #endif
42 struct task_struct *task;
43
44 struct stack_info stack;
45 struct stack_info *stacks;
46 int nr_stacks;
47 };
48
stackinfo_get_unknown(void)49 static inline struct stack_info stackinfo_get_unknown(void)
50 {
51 return (struct stack_info) {
52 .low = 0,
53 .high = 0,
54 };
55 }
56
stackinfo_on_stack(const struct stack_info * info,unsigned long sp,unsigned long size)57 static inline bool stackinfo_on_stack(const struct stack_info *info,
58 unsigned long sp, unsigned long size)
59 {
60 if (!info->low)
61 return false;
62
63 if (sp < info->low || sp + size < sp || sp + size > info->high)
64 return false;
65
66 return true;
67 }
68
unwind_init_common(struct unwind_state * state,struct task_struct * task)69 static inline void unwind_init_common(struct unwind_state *state,
70 struct task_struct *task)
71 {
72 state->task = task;
73 #ifdef CONFIG_KRETPROBES
74 state->kr_cur = NULL;
75 #endif
76
77 state->stack = stackinfo_get_unknown();
78 }
79
unwind_find_next_stack(const struct unwind_state * state,unsigned long sp,unsigned long size)80 static struct stack_info *unwind_find_next_stack(const struct unwind_state *state,
81 unsigned long sp,
82 unsigned long size)
83 {
84 for (int i = 0; i < state->nr_stacks; i++) {
85 struct stack_info *info = &state->stacks[i];
86
87 if (stackinfo_on_stack(info, sp, size))
88 return info;
89 }
90
91 return NULL;
92 }
93
94 /**
95 * unwind_consume_stack() - Check if an object is on an accessible stack,
96 * updating stack boundaries so that future unwind steps cannot consume this
97 * object again.
98 *
99 * @state: the current unwind state.
100 * @sp: the base address of the object.
101 * @size: the size of the object.
102 *
103 * Return: 0 upon success, an error code otherwise.
104 */
unwind_consume_stack(struct unwind_state * state,unsigned long sp,unsigned long size)105 static inline int unwind_consume_stack(struct unwind_state *state,
106 unsigned long sp,
107 unsigned long size)
108 {
109 struct stack_info *next;
110
111 if (stackinfo_on_stack(&state->stack, sp, size))
112 goto found;
113
114 next = unwind_find_next_stack(state, sp, size);
115 if (!next)
116 return -EINVAL;
117
118 /*
119 * Stack transitions are strictly one-way, and once we've
120 * transitioned from one stack to another, it's never valid to
121 * unwind back to the old stack.
122 *
123 * Remove the current stack from the list of stacks so that it cannot
124 * be found on a subsequent transition.
125 *
126 * Note that stacks can nest in several valid orders, e.g.
127 *
128 * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL
129 * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW
130 * HYP -> OVERFLOW
131 *
132 * ... so we do not check the specific order of stack
133 * transitions.
134 */
135 state->stack = *next;
136 *next = stackinfo_get_unknown();
137
138 found:
139 /*
140 * Future unwind steps can only consume stack above this frame record.
141 * Update the current stack to start immediately above it.
142 */
143 state->stack.low = sp + size;
144 return 0;
145 }
146
147 /**
148 * unwind_next_frame_record() - Unwind to the next frame record.
149 *
150 * @state: the current unwind state.
151 *
152 * Return: 0 upon success, an error code otherwise.
153 */
154 static inline int
unwind_next_frame_record(struct unwind_state * state)155 unwind_next_frame_record(struct unwind_state *state)
156 {
157 unsigned long fp = state->fp;
158 int err;
159
160 if (fp & 0x7)
161 return -EINVAL;
162
163 err = unwind_consume_stack(state, fp, 16);
164 if (err)
165 return err;
166
167 /*
168 * Record this frame record's values.
169 */
170 state->fp = READ_ONCE(*(unsigned long *)(fp));
171 state->pc = READ_ONCE(*(unsigned long *)(fp + 8));
172
173 return 0;
174 }
175
176 #endif /* __ASM_STACKTRACE_COMMON_H */
177