xref: /openbmc/linux/arch/xtensa/kernel/stacktrace.c (revision 23c2b932)
1 /*
2  * Kernel and userspace stack tracing.
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 2001 - 2013 Tensilica Inc.
9  * Copyright (C) 2015 Cadence Design Systems Inc.
10  */
11 #include <linux/export.h>
12 #include <linux/sched.h>
13 #include <linux/stacktrace.h>
14 
15 #include <asm/stacktrace.h>
16 #include <asm/traps.h>
17 #include <asm/uaccess.h>
18 
19 #if IS_ENABLED(CONFIG_OPROFILE) || IS_ENABLED(CONFIG_PERF_EVENTS)
20 
21 /* Address of common_exception_return, used to check the
22  * transition from kernel to user space.
23  */
24 extern int common_exception_return;
25 
26 /* A struct that maps to the part of the frame containing the a0 and
27  * a1 registers.
28  */
29 struct frame_start {
30 	unsigned long a0;
31 	unsigned long a1;
32 };
33 
34 void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
35 			   int (*ufn)(struct stackframe *frame, void *data),
36 			   void *data)
37 {
38 	unsigned long windowstart = regs->windowstart;
39 	unsigned long windowbase = regs->windowbase;
40 	unsigned long a0 = regs->areg[0];
41 	unsigned long a1 = regs->areg[1];
42 	unsigned long pc = regs->pc;
43 	struct stackframe frame;
44 	int index;
45 
46 	if (!depth--)
47 		return;
48 
49 	frame.pc = pc;
50 	frame.sp = a1;
51 
52 	if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
53 		return;
54 
55 	/* Two steps:
56 	 *
57 	 * 1. Look through the register window for the
58 	 * previous PCs in the call trace.
59 	 *
60 	 * 2. Look on the stack.
61 	 */
62 
63 	/* Step 1.  */
64 	/* Rotate WINDOWSTART to move the bit corresponding to
65 	 * the current window to the bit #0.
66 	 */
67 	windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
68 
69 	/* Look for bits that are set, they correspond to
70 	 * valid windows.
71 	 */
72 	for (index = WSBITS - 1; (index > 0) && depth; depth--, index--)
73 		if (windowstart & (1 << index)) {
74 			/* Get the PC from a0 and a1. */
75 			pc = MAKE_PC_FROM_RA(a0, pc);
76 			/* Read a0 and a1 from the
77 			 * corresponding position in AREGs.
78 			 */
79 			a0 = regs->areg[index * 4];
80 			a1 = regs->areg[index * 4 + 1];
81 
82 			frame.pc = pc;
83 			frame.sp = a1;
84 
85 			if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
86 				return;
87 		}
88 
89 	/* Step 2. */
90 	/* We are done with the register window, we need to
91 	 * look through the stack.
92 	 */
93 	if (!depth)
94 		return;
95 
96 	/* Start from the a1 register. */
97 	/* a1 = regs->areg[1]; */
98 	while (a0 != 0 && depth--) {
99 		struct frame_start frame_start;
100 		/* Get the location for a1, a0 for the
101 		 * previous frame from the current a1.
102 		 */
103 		unsigned long *psp = (unsigned long *)a1;
104 
105 		psp -= 4;
106 
107 		/* Check if the region is OK to access. */
108 		if (!access_ok(VERIFY_READ, psp, sizeof(frame_start)))
109 			return;
110 		/* Copy a1, a0 from user space stack frame. */
111 		if (__copy_from_user_inatomic(&frame_start, psp,
112 					      sizeof(frame_start)))
113 			return;
114 
115 		pc = MAKE_PC_FROM_RA(a0, pc);
116 		a0 = frame_start.a0;
117 		a1 = frame_start.a1;
118 
119 		frame.pc = pc;
120 		frame.sp = a1;
121 
122 		if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
123 			return;
124 	}
125 }
126 EXPORT_SYMBOL(xtensa_backtrace_user);
127 
128 void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
129 			     int (*kfn)(struct stackframe *frame, void *data),
130 			     int (*ufn)(struct stackframe *frame, void *data),
131 			     void *data)
132 {
133 	unsigned long pc = regs->depc > VALID_DOUBLE_EXCEPTION_ADDRESS ?
134 		regs->depc : regs->pc;
135 	unsigned long sp_start, sp_end;
136 	unsigned long a0 = regs->areg[0];
137 	unsigned long a1 = regs->areg[1];
138 
139 	sp_start = a1 & ~(THREAD_SIZE - 1);
140 	sp_end = sp_start + THREAD_SIZE;
141 
142 	/* Spill the register window to the stack first. */
143 	spill_registers();
144 
145 	/* Read the stack frames one by one and create the PC
146 	 * from the a0 and a1 registers saved there.
147 	 */
148 	while (a1 > sp_start && a1 < sp_end && depth--) {
149 		struct stackframe frame;
150 		unsigned long *psp = (unsigned long *)a1;
151 
152 		frame.pc = pc;
153 		frame.sp = a1;
154 
155 		if (kernel_text_address(pc) && kfn(&frame, data))
156 			return;
157 
158 		if (pc == (unsigned long)&common_exception_return) {
159 			regs = (struct pt_regs *)a1;
160 			if (user_mode(regs)) {
161 				if (ufn == NULL)
162 					return;
163 				xtensa_backtrace_user(regs, depth, ufn, data);
164 				return;
165 			}
166 			a0 = regs->areg[0];
167 			a1 = regs->areg[1];
168 			continue;
169 		}
170 
171 		sp_start = a1;
172 
173 		pc = MAKE_PC_FROM_RA(a0, pc);
174 		a0 = *(psp - 4);
175 		a1 = *(psp - 3);
176 	}
177 }
178 EXPORT_SYMBOL(xtensa_backtrace_kernel);
179 
180 #endif
181 
182 void walk_stackframe(unsigned long *sp,
183 		int (*fn)(struct stackframe *frame, void *data),
184 		void *data)
185 {
186 	unsigned long a0, a1;
187 	unsigned long sp_end;
188 
189 	a1 = (unsigned long)sp;
190 	sp_end = ALIGN(a1, THREAD_SIZE);
191 
192 	spill_registers();
193 
194 	while (a1 < sp_end) {
195 		struct stackframe frame;
196 
197 		sp = (unsigned long *)a1;
198 
199 		a0 = *(sp - 4);
200 		a1 = *(sp - 3);
201 
202 		if (a1 <= (unsigned long)sp)
203 			break;
204 
205 		frame.pc = MAKE_PC_FROM_RA(a0, a1);
206 		frame.sp = a1;
207 
208 		if (fn(&frame, data))
209 			return;
210 	}
211 }
212 
213 #ifdef CONFIG_STACKTRACE
214 
215 struct stack_trace_data {
216 	struct stack_trace *trace;
217 	unsigned skip;
218 };
219 
220 static int stack_trace_cb(struct stackframe *frame, void *data)
221 {
222 	struct stack_trace_data *trace_data = data;
223 	struct stack_trace *trace = trace_data->trace;
224 
225 	if (trace_data->skip) {
226 		--trace_data->skip;
227 		return 0;
228 	}
229 	if (!kernel_text_address(frame->pc))
230 		return 0;
231 
232 	trace->entries[trace->nr_entries++] = frame->pc;
233 	return trace->nr_entries >= trace->max_entries;
234 }
235 
236 void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace)
237 {
238 	struct stack_trace_data trace_data = {
239 		.trace = trace,
240 		.skip = trace->skip,
241 	};
242 	walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data);
243 }
244 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
245 
246 void save_stack_trace(struct stack_trace *trace)
247 {
248 	save_stack_trace_tsk(current, trace);
249 }
250 EXPORT_SYMBOL_GPL(save_stack_trace);
251 
252 #endif
253 
254 #ifdef CONFIG_FRAME_POINTER
255 
256 struct return_addr_data {
257 	unsigned long addr;
258 	unsigned skip;
259 };
260 
261 static int return_address_cb(struct stackframe *frame, void *data)
262 {
263 	struct return_addr_data *r = data;
264 
265 	if (r->skip) {
266 		--r->skip;
267 		return 0;
268 	}
269 	if (!kernel_text_address(frame->pc))
270 		return 0;
271 	r->addr = frame->pc;
272 	return 1;
273 }
274 
275 unsigned long return_address(unsigned level)
276 {
277 	struct return_addr_data r = {
278 		.skip = level + 1,
279 	};
280 	walk_stackframe(stack_pointer(NULL), return_address_cb, &r);
281 	return r.addr;
282 }
283 EXPORT_SYMBOL(return_address);
284 
285 #endif
286