GNU Linux-libre 5.4.274-gnu1
[releases.git] / arch / arm / kernel / stacktrace.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/export.h>
3 #include <linux/sched.h>
4 #include <linux/sched/debug.h>
5 #include <linux/stacktrace.h>
6
7 #include <asm/sections.h>
8 #include <asm/stacktrace.h>
9 #include <asm/traps.h>
10
11 #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
12 /*
13  * Unwind the current stack frame and store the new register values in the
14  * structure passed as argument. Unwinding is equivalent to a function return,
15  * hence the new PC value rather than LR should be used for backtrace.
16  *
17  * With framepointer enabled, a simple function prologue looks like this:
18  *      mov     ip, sp
19  *      stmdb   sp!, {fp, ip, lr, pc}
20  *      sub     fp, ip, #4
21  *
22  * A simple function epilogue looks like this:
23  *      ldm     sp, {fp, sp, pc}
24  *
25  * When compiled with clang, pc and sp are not pushed. A simple function
26  * prologue looks like this when built with clang:
27  *
28  *      stmdb   {..., fp, lr}
29  *      add     fp, sp, #x
30  *      sub     sp, sp, #y
31  *
32  * A simple function epilogue looks like this when built with clang:
33  *
34  *      sub     sp, fp, #x
35  *      ldm     {..., fp, pc}
36  *
37  *
38  * Note that with framepointer enabled, even the leaf functions have the same
39  * prologue and epilogue, therefore we can ignore the LR value in this case.
40  */
41 int notrace unwind_frame(struct stackframe *frame)
42 {
43         unsigned long high, low;
44         unsigned long fp = frame->fp;
45
46         /* only go to a higher address on the stack */
47         low = frame->sp;
48         high = ALIGN(low, THREAD_SIZE);
49
50 #ifdef CONFIG_CC_IS_CLANG
51         /* check current frame pointer is within bounds */
52         if (fp < low + 4 || fp > high - 4)
53                 return -EINVAL;
54
55         frame->sp = frame->fp;
56         frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
57         frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
58 #else
59         /* check current frame pointer is within bounds */
60         if (fp < low + 12 || fp > high - 4)
61                 return -EINVAL;
62
63         /* restore the registers from the stack frame */
64         frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12));
65         frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8));
66         frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4));
67 #endif
68
69         return 0;
70 }
71 #endif
72
73 void notrace walk_stackframe(struct stackframe *frame,
74                      int (*fn)(struct stackframe *, void *), void *data)
75 {
76         while (1) {
77                 int ret;
78
79                 if (fn(frame, data))
80                         break;
81                 ret = unwind_frame(frame);
82                 if (ret < 0)
83                         break;
84         }
85 }
86 EXPORT_SYMBOL(walk_stackframe);
87
88 #ifdef CONFIG_STACKTRACE
89 struct stack_trace_data {
90         struct stack_trace *trace;
91         unsigned int no_sched_functions;
92         unsigned int skip;
93 };
94
95 static int save_trace(struct stackframe *frame, void *d)
96 {
97         struct stack_trace_data *data = d;
98         struct stack_trace *trace = data->trace;
99         struct pt_regs *regs;
100         unsigned long addr = frame->pc;
101
102         if (data->no_sched_functions && in_sched_functions(addr))
103                 return 0;
104         if (data->skip) {
105                 data->skip--;
106                 return 0;
107         }
108
109         trace->entries[trace->nr_entries++] = addr;
110
111         if (trace->nr_entries >= trace->max_entries)
112                 return 1;
113
114         if (!in_entry_text(frame->pc))
115                 return 0;
116
117         regs = (struct pt_regs *)frame->sp;
118         if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
119                 return 0;
120
121         trace->entries[trace->nr_entries++] = regs->ARM_pc;
122
123         return trace->nr_entries >= trace->max_entries;
124 }
125
126 /* This must be noinline to so that our skip calculation works correctly */
127 static noinline void __save_stack_trace(struct task_struct *tsk,
128         struct stack_trace *trace, unsigned int nosched)
129 {
130         struct stack_trace_data data;
131         struct stackframe frame;
132
133         data.trace = trace;
134         data.skip = trace->skip;
135         data.no_sched_functions = nosched;
136
137         if (tsk != current) {
138 #ifdef CONFIG_SMP
139                 /*
140                  * What guarantees do we have here that 'tsk' is not
141                  * running on another CPU?  For now, ignore it as we
142                  * can't guarantee we won't explode.
143                  */
144                 return;
145 #else
146                 frame.fp = thread_saved_fp(tsk);
147                 frame.sp = thread_saved_sp(tsk);
148                 frame.lr = 0;           /* recovered from the stack */
149                 frame.pc = thread_saved_pc(tsk);
150 #endif
151         } else {
152                 /* We don't want this function nor the caller */
153                 data.skip += 2;
154                 frame.fp = (unsigned long)__builtin_frame_address(0);
155                 frame.sp = current_stack_pointer;
156                 frame.lr = (unsigned long)__builtin_return_address(0);
157                 frame.pc = (unsigned long)__save_stack_trace;
158         }
159
160         walk_stackframe(&frame, save_trace, &data);
161 }
162
163 void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
164 {
165         struct stack_trace_data data;
166         struct stackframe frame;
167
168         data.trace = trace;
169         data.skip = trace->skip;
170         data.no_sched_functions = 0;
171
172         frame.fp = regs->ARM_fp;
173         frame.sp = regs->ARM_sp;
174         frame.lr = regs->ARM_lr;
175         frame.pc = regs->ARM_pc;
176
177         walk_stackframe(&frame, save_trace, &data);
178 }
179
180 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
181 {
182         __save_stack_trace(tsk, trace, 1);
183 }
184 EXPORT_SYMBOL(save_stack_trace_tsk);
185
186 void save_stack_trace(struct stack_trace *trace)
187 {
188         __save_stack_trace(current, trace, 0);
189 }
190 EXPORT_SYMBOL_GPL(save_stack_trace);
191 #endif