stacktrace.c (5854e4d8530e6ed4c2532a71a6b0474e199d44dd) stacktrace.c (752ec621ef5c30777958cc5eb5f1cf394f7733f4)
1// SPDX-License-Identifier: GPL-2.0-only
2#include <linux/export.h>
3#include <linux/kprobes.h>
4#include <linux/sched.h>
5#include <linux/sched/debug.h>
6#include <linux/stacktrace.h>
7
8#include <asm/sections.h>

--- 68 unchanged lines hidden (view full) ---

77
78int notrace unwind_frame(struct stackframe *frame)
79{
80 unsigned long fp = frame->fp;
81
82 if (frame_pointer_check(frame))
83 return -EINVAL;
84
1// SPDX-License-Identifier: GPL-2.0-only
2#include <linux/export.h>
3#include <linux/kprobes.h>
4#include <linux/sched.h>
5#include <linux/sched/debug.h>
6#include <linux/stacktrace.h>
7
8#include <asm/sections.h>

--- 68 unchanged lines hidden (view full) ---

77
78int notrace unwind_frame(struct stackframe *frame)
79{
80 unsigned long fp = frame->fp;
81
82 if (frame_pointer_check(frame))
83 return -EINVAL;
84
85 /*
86 * When we unwind through an exception stack, include the saved PC
87 * value into the stack trace.
88 */
89 if (frame->ex_frame) {
90 struct pt_regs *regs = (struct pt_regs *)frame->sp;
91
92 /*
93 * We check that 'regs + sizeof(struct pt_regs)' (that is,
94 * &regs[1]) does not exceed the bottom of the stack to avoid
95 * accessing data outside the task's stack. This may happen
96 * when frame->ex_frame is a false positive.
97 */
98 if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
99 return -EINVAL;
100
101 frame->pc = regs->ARM_pc;
102 frame->ex_frame = false;
103 return 0;
104 }
105
85 /* restore the registers from the stack frame */
86#ifdef CONFIG_CC_IS_CLANG
87 frame->sp = frame->fp;
88 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
89 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
90#else
91 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12));
92 frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8));
93 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4));
94#endif
95#ifdef CONFIG_KRETPROBES
96 if (is_kretprobe_trampoline(frame->pc))
97 frame->pc = kretprobe_find_ret_addr(frame->tsk,
98 (void *)frame->fp, &frame->kr_cur);
99#endif
100
106 /* restore the registers from the stack frame */
107#ifdef CONFIG_CC_IS_CLANG
108 frame->sp = frame->fp;
109 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
110 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
111#else
112 frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12));
113 frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8));
114 frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4));
115#endif
116#ifdef CONFIG_KRETPROBES
117 if (is_kretprobe_trampoline(frame->pc))
118 frame->pc = kretprobe_find_ret_addr(frame->tsk,
119 (void *)frame->fp, &frame->kr_cur);
120#endif
121
122 if (in_entry_text(frame->pc))
123 frame->ex_frame = true;
124
101 return 0;
102}
103#endif
104
105void notrace walk_stackframe(struct stackframe *frame,
106 int (*fn)(struct stackframe *, void *), void *data)
107{
108 while (1) {

--- 14 unchanged lines hidden (view full) ---

123 unsigned int no_sched_functions;
124 unsigned int skip;
125};
126
127static int save_trace(struct stackframe *frame, void *d)
128{
129 struct stack_trace_data *data = d;
130 struct stack_trace *trace = data->trace;
125 return 0;
126}
127#endif
128
129void notrace walk_stackframe(struct stackframe *frame,
130 int (*fn)(struct stackframe *, void *), void *data)
131{
132 while (1) {

--- 14 unchanged lines hidden (view full) ---

147 unsigned int no_sched_functions;
148 unsigned int skip;
149};
150
151static int save_trace(struct stackframe *frame, void *d)
152{
153 struct stack_trace_data *data = d;
154 struct stack_trace *trace = data->trace;
131 struct pt_regs *regs;
132 unsigned long addr = frame->pc;
133
134 if (data->no_sched_functions && in_sched_functions(addr))
135 return 0;
136 if (data->skip) {
137 data->skip--;
138 return 0;
139 }
140
141 trace->entries[trace->nr_entries++] = addr;
155 unsigned long addr = frame->pc;
156
157 if (data->no_sched_functions && in_sched_functions(addr))
158 return 0;
159 if (data->skip) {
160 data->skip--;
161 return 0;
162 }
163
164 trace->entries[trace->nr_entries++] = addr;
142
143 if (trace->nr_entries >= trace->max_entries)
144 return 1;
145
146 if (!in_entry_text(frame->pc))
147 return 0;
148
149 regs = (struct pt_regs *)frame->sp;
150 if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
151 return 0;
152
153 trace->entries[trace->nr_entries++] = regs->ARM_pc;
154
155 return trace->nr_entries >= trace->max_entries;
156}
157
158/* This must be noinline to so that our skip calculation works correctly */
159static noinline void __save_stack_trace(struct task_struct *tsk,
160 struct stack_trace *trace, unsigned int nosched)
161{
162 struct stack_trace_data data;

--- 25 unchanged lines hidden (view full) ---

188 frame.lr = (unsigned long)__builtin_return_address(0);
189here:
190 frame.pc = (unsigned long)&&here;
191 }
192#ifdef CONFIG_KRETPROBES
193 frame.kr_cur = NULL;
194 frame.tsk = tsk;
195#endif
165 return trace->nr_entries >= trace->max_entries;
166}
167
168/* This must be noinline to so that our skip calculation works correctly */
169static noinline void __save_stack_trace(struct task_struct *tsk,
170 struct stack_trace *trace, unsigned int nosched)
171{
172 struct stack_trace_data data;

--- 25 unchanged lines hidden (view full) ---

198 frame.lr = (unsigned long)__builtin_return_address(0);
199here:
200 frame.pc = (unsigned long)&&here;
201 }
202#ifdef CONFIG_KRETPROBES
203 frame.kr_cur = NULL;
204 frame.tsk = tsk;
205#endif
206#ifdef CONFIG_UNWINDER_FRAME_POINTER
207 frame.ex_frame = false;
208#endif
196
197 walk_stackframe(&frame, save_trace, &data);
198}
199
200void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
201{
202 struct stack_trace_data data;
203 struct stackframe frame;

--- 5 unchanged lines hidden (view full) ---

209 frame.fp = regs->ARM_fp;
210 frame.sp = regs->ARM_sp;
211 frame.lr = regs->ARM_lr;
212 frame.pc = regs->ARM_pc;
213#ifdef CONFIG_KRETPROBES
214 frame.kr_cur = NULL;
215 frame.tsk = current;
216#endif
209
210 walk_stackframe(&frame, save_trace, &data);
211}
212
213void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
214{
215 struct stack_trace_data data;
216 struct stackframe frame;

--- 5 unchanged lines hidden (view full) ---

222 frame.fp = regs->ARM_fp;
223 frame.sp = regs->ARM_sp;
224 frame.lr = regs->ARM_lr;
225 frame.pc = regs->ARM_pc;
226#ifdef CONFIG_KRETPROBES
227 frame.kr_cur = NULL;
228 frame.tsk = current;
229#endif
230#ifdef CONFIG_UNWINDER_FRAME_POINTER
231 frame.ex_frame = in_entry_text(frame.pc);
232#endif
217
218 walk_stackframe(&frame, save_trace, &data);
219}
220
221void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
222{
223 __save_stack_trace(tsk, trace, 1);
224}
225EXPORT_SYMBOL(save_stack_trace_tsk);
226
227void save_stack_trace(struct stack_trace *trace)
228{
229 __save_stack_trace(current, trace, 0);
230}
231EXPORT_SYMBOL_GPL(save_stack_trace);
232#endif
233
234 walk_stackframe(&frame, save_trace, &data);
235}
236
237void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
238{
239 __save_stack_trace(tsk, trace, 1);
240}
241EXPORT_SYMBOL(save_stack_trace_tsk);
242
243void save_stack_trace(struct stack_trace *trace)
244{
245 __save_stack_trace(current, trace, 0);
246}
247EXPORT_SYMBOL_GPL(save_stack_trace);
248#endif