xref: /openbmc/linux/arch/xtensa/kernel/stacktrace.c (revision ef31b464)
13e4196a5SMax Filippov /*
25fdf377dSMax Filippov  * Kernel and userspace stack tracing.
33e4196a5SMax Filippov  *
43e4196a5SMax Filippov  * This file is subject to the terms and conditions of the GNU General Public
53e4196a5SMax Filippov  * License.  See the file "COPYING" in the main directory of this archive
63e4196a5SMax Filippov  * for more details.
73e4196a5SMax Filippov  *
83e4196a5SMax Filippov  * Copyright (C) 2001 - 2013 Tensilica Inc.
95fdf377dSMax Filippov  * Copyright (C) 2015 Cadence Design Systems Inc.
103e4196a5SMax Filippov  */
113e4196a5SMax Filippov #include <linux/export.h>
123e4196a5SMax Filippov #include <linux/sched.h>
133e4196a5SMax Filippov #include <linux/stacktrace.h>
143e4196a5SMax Filippov 
151b6ceeb9SRandy Dunlap #include <asm/ftrace.h>
16ef31b464SMax Filippov #include <asm/sections.h>
173e4196a5SMax Filippov #include <asm/stacktrace.h>
183e4196a5SMax Filippov #include <asm/traps.h>
197c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
205fdf377dSMax Filippov 
21a848bf1dSViresh Kumar #if IS_ENABLED(CONFIG_PERF_EVENTS)
225fdf377dSMax Filippov 
235fdf377dSMax Filippov /* Address of common_exception_return, used to check the
245fdf377dSMax Filippov  * transition from kernel to user space.
255fdf377dSMax Filippov  */
265fdf377dSMax Filippov extern int common_exception_return;
275fdf377dSMax Filippov 
xtensa_backtrace_user(struct pt_regs * regs,unsigned int depth,int (* ufn)(struct stackframe * frame,void * data),void * data)285fdf377dSMax Filippov void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
295fdf377dSMax Filippov 			   int (*ufn)(struct stackframe *frame, void *data),
305fdf377dSMax Filippov 			   void *data)
315fdf377dSMax Filippov {
325fdf377dSMax Filippov 	unsigned long windowstart = regs->windowstart;
335fdf377dSMax Filippov 	unsigned long windowbase = regs->windowbase;
345fdf377dSMax Filippov 	unsigned long a0 = regs->areg[0];
355fdf377dSMax Filippov 	unsigned long a1 = regs->areg[1];
365fdf377dSMax Filippov 	unsigned long pc = regs->pc;
375fdf377dSMax Filippov 	struct stackframe frame;
385fdf377dSMax Filippov 	int index;
395fdf377dSMax Filippov 
405fdf377dSMax Filippov 	if (!depth--)
415fdf377dSMax Filippov 		return;
425fdf377dSMax Filippov 
435fdf377dSMax Filippov 	frame.pc = pc;
445fdf377dSMax Filippov 	frame.sp = a1;
455fdf377dSMax Filippov 
465fdf377dSMax Filippov 	if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
475fdf377dSMax Filippov 		return;
485fdf377dSMax Filippov 
4909f8a6dbSMax Filippov 	if (IS_ENABLED(CONFIG_USER_ABI_CALL0_ONLY) ||
5009f8a6dbSMax Filippov 	    (IS_ENABLED(CONFIG_USER_ABI_CALL0_PROBE) &&
5109f8a6dbSMax Filippov 	     !(regs->ps & PS_WOE_MASK)))
5209f8a6dbSMax Filippov 		return;
5309f8a6dbSMax Filippov 
545fdf377dSMax Filippov 	/* Two steps:
555fdf377dSMax Filippov 	 *
565fdf377dSMax Filippov 	 * 1. Look through the register window for the
575fdf377dSMax Filippov 	 * previous PCs in the call trace.
585fdf377dSMax Filippov 	 *
595fdf377dSMax Filippov 	 * 2. Look on the stack.
605fdf377dSMax Filippov 	 */
615fdf377dSMax Filippov 
625fdf377dSMax Filippov 	/* Step 1.  */
635fdf377dSMax Filippov 	/* Rotate WINDOWSTART to move the bit corresponding to
645fdf377dSMax Filippov 	 * the current window to the bit #0.
655fdf377dSMax Filippov 	 */
665fdf377dSMax Filippov 	windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
675fdf377dSMax Filippov 
685fdf377dSMax Filippov 	/* Look for bits that are set, they correspond to
695fdf377dSMax Filippov 	 * valid windows.
705fdf377dSMax Filippov 	 */
715fdf377dSMax Filippov 	for (index = WSBITS - 1; (index > 0) && depth; depth--, index--)
725fdf377dSMax Filippov 		if (windowstart & (1 << index)) {
735fdf377dSMax Filippov 			/* Get the PC from a0 and a1. */
745fdf377dSMax Filippov 			pc = MAKE_PC_FROM_RA(a0, pc);
755fdf377dSMax Filippov 			/* Read a0 and a1 from the
765fdf377dSMax Filippov 			 * corresponding position in AREGs.
775fdf377dSMax Filippov 			 */
785fdf377dSMax Filippov 			a0 = regs->areg[index * 4];
795fdf377dSMax Filippov 			a1 = regs->areg[index * 4 + 1];
805fdf377dSMax Filippov 
815fdf377dSMax Filippov 			frame.pc = pc;
825fdf377dSMax Filippov 			frame.sp = a1;
835fdf377dSMax Filippov 
845fdf377dSMax Filippov 			if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
855fdf377dSMax Filippov 				return;
865fdf377dSMax Filippov 		}
875fdf377dSMax Filippov 
885fdf377dSMax Filippov 	/* Step 2. */
895fdf377dSMax Filippov 	/* We are done with the register window, we need to
905fdf377dSMax Filippov 	 * look through the stack.
915fdf377dSMax Filippov 	 */
925fdf377dSMax Filippov 	if (!depth)
935fdf377dSMax Filippov 		return;
945fdf377dSMax Filippov 
955fdf377dSMax Filippov 	/* Start from the a1 register. */
965fdf377dSMax Filippov 	/* a1 = regs->areg[1]; */
975fdf377dSMax Filippov 	while (a0 != 0 && depth--) {
98062b1c19SMax Filippov 		pc = MAKE_PC_FROM_RA(a0, pc);
995fdf377dSMax Filippov 
1005fdf377dSMax Filippov 		/* Check if the region is OK to access. */
10196d4f267SLinus Torvalds 		if (!access_ok(&SPILL_SLOT(a1, 0), 8))
1025fdf377dSMax Filippov 			return;
1035fdf377dSMax Filippov 		/* Copy a1, a0 from user space stack frame. */
104062b1c19SMax Filippov 		if (__get_user(a0, &SPILL_SLOT(a1, 0)) ||
105062b1c19SMax Filippov 		    __get_user(a1, &SPILL_SLOT(a1, 1)))
1065fdf377dSMax Filippov 			return;
1075fdf377dSMax Filippov 
1085fdf377dSMax Filippov 		frame.pc = pc;
1095fdf377dSMax Filippov 		frame.sp = a1;
1105fdf377dSMax Filippov 
1115fdf377dSMax Filippov 		if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
1125fdf377dSMax Filippov 			return;
1135fdf377dSMax Filippov 	}
1145fdf377dSMax Filippov }
1155fdf377dSMax Filippov EXPORT_SYMBOL(xtensa_backtrace_user);
1165fdf377dSMax Filippov 
xtensa_backtrace_kernel(struct pt_regs * regs,unsigned int depth,int (* kfn)(struct stackframe * frame,void * data),int (* ufn)(struct stackframe * frame,void * data),void * data)1175fdf377dSMax Filippov void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
1185fdf377dSMax Filippov 			     int (*kfn)(struct stackframe *frame, void *data),
1195fdf377dSMax Filippov 			     int (*ufn)(struct stackframe *frame, void *data),
1205fdf377dSMax Filippov 			     void *data)
1215fdf377dSMax Filippov {
1225fdf377dSMax Filippov 	unsigned long pc = regs->depc > VALID_DOUBLE_EXCEPTION_ADDRESS ?
1235fdf377dSMax Filippov 		regs->depc : regs->pc;
1245fdf377dSMax Filippov 	unsigned long sp_start, sp_end;
1255fdf377dSMax Filippov 	unsigned long a0 = regs->areg[0];
1265fdf377dSMax Filippov 	unsigned long a1 = regs->areg[1];
1275fdf377dSMax Filippov 
1285fdf377dSMax Filippov 	sp_start = a1 & ~(THREAD_SIZE - 1);
1295fdf377dSMax Filippov 	sp_end = sp_start + THREAD_SIZE;
1305fdf377dSMax Filippov 
1315fdf377dSMax Filippov 	/* Spill the register window to the stack first. */
1325fdf377dSMax Filippov 	spill_registers();
1335fdf377dSMax Filippov 
1345fdf377dSMax Filippov 	/* Read the stack frames one by one and create the PC
1355fdf377dSMax Filippov 	 * from the a0 and a1 registers saved there.
1365fdf377dSMax Filippov 	 */
1375fdf377dSMax Filippov 	while (a1 > sp_start && a1 < sp_end && depth--) {
1385fdf377dSMax Filippov 		struct stackframe frame;
1395fdf377dSMax Filippov 
1405fdf377dSMax Filippov 		frame.pc = pc;
1415fdf377dSMax Filippov 		frame.sp = a1;
1425fdf377dSMax Filippov 
1435fdf377dSMax Filippov 		if (kernel_text_address(pc) && kfn(&frame, data))
1445fdf377dSMax Filippov 			return;
1455fdf377dSMax Filippov 
1465fdf377dSMax Filippov 		if (pc == (unsigned long)&common_exception_return) {
1475fdf377dSMax Filippov 			regs = (struct pt_regs *)a1;
1485fdf377dSMax Filippov 			if (user_mode(regs)) {
1495fdf377dSMax Filippov 				if (ufn == NULL)
1505fdf377dSMax Filippov 					return;
1515fdf377dSMax Filippov 				xtensa_backtrace_user(regs, depth, ufn, data);
1525fdf377dSMax Filippov 				return;
1535fdf377dSMax Filippov 			}
1545fdf377dSMax Filippov 			a0 = regs->areg[0];
1555fdf377dSMax Filippov 			a1 = regs->areg[1];
1565fdf377dSMax Filippov 			continue;
1575fdf377dSMax Filippov 		}
1585fdf377dSMax Filippov 
1595fdf377dSMax Filippov 		sp_start = a1;
1605fdf377dSMax Filippov 
1615fdf377dSMax Filippov 		pc = MAKE_PC_FROM_RA(a0, pc);
162062b1c19SMax Filippov 		a0 = SPILL_SLOT(a1, 0);
163062b1c19SMax Filippov 		a1 = SPILL_SLOT(a1, 1);
1645fdf377dSMax Filippov 	}
1655fdf377dSMax Filippov }
1665fdf377dSMax Filippov EXPORT_SYMBOL(xtensa_backtrace_kernel);
1675fdf377dSMax Filippov 
1685fdf377dSMax Filippov #endif
1693e4196a5SMax Filippov 
walk_stackframe(unsigned long * sp,int (* fn)(struct stackframe * frame,void * data),void * data)1703e4196a5SMax Filippov void walk_stackframe(unsigned long *sp,
1713e4196a5SMax Filippov 		int (*fn)(struct stackframe *frame, void *data),
1723e4196a5SMax Filippov 		void *data)
1733e4196a5SMax Filippov {
1743e4196a5SMax Filippov 	unsigned long a0, a1;
1753e4196a5SMax Filippov 	unsigned long sp_end;
1763e4196a5SMax Filippov 
1773e4196a5SMax Filippov 	a1 = (unsigned long)sp;
1783e4196a5SMax Filippov 	sp_end = ALIGN(a1, THREAD_SIZE);
1793e4196a5SMax Filippov 
1803e4196a5SMax Filippov 	spill_registers();
1813e4196a5SMax Filippov 
1823e4196a5SMax Filippov 	while (a1 < sp_end) {
1833e4196a5SMax Filippov 		struct stackframe frame;
1843e4196a5SMax Filippov 
1853e4196a5SMax Filippov 		sp = (unsigned long *)a1;
1863e4196a5SMax Filippov 
187062b1c19SMax Filippov 		a0 = SPILL_SLOT(a1, 0);
188062b1c19SMax Filippov 		a1 = SPILL_SLOT(a1, 1);
1893e4196a5SMax Filippov 
1903e4196a5SMax Filippov 		if (a1 <= (unsigned long)sp)
1913e4196a5SMax Filippov 			break;
1923e4196a5SMax Filippov 
193ef31b464SMax Filippov 		frame.pc = MAKE_PC_FROM_RA(a0, _text);
1943e4196a5SMax Filippov 		frame.sp = a1;
1953e4196a5SMax Filippov 
1963e4196a5SMax Filippov 		if (fn(&frame, data))
1973e4196a5SMax Filippov 			return;
1983e4196a5SMax Filippov 	}
1993e4196a5SMax Filippov }
2003e4196a5SMax Filippov 
2013e4196a5SMax Filippov #ifdef CONFIG_STACKTRACE
2023e4196a5SMax Filippov 
2033e4196a5SMax Filippov struct stack_trace_data {
2043e4196a5SMax Filippov 	struct stack_trace *trace;
2053e4196a5SMax Filippov 	unsigned skip;
2063e4196a5SMax Filippov };
2073e4196a5SMax Filippov 
stack_trace_cb(struct stackframe * frame,void * data)2083e4196a5SMax Filippov static int stack_trace_cb(struct stackframe *frame, void *data)
2093e4196a5SMax Filippov {
2103e4196a5SMax Filippov 	struct stack_trace_data *trace_data = data;
2113e4196a5SMax Filippov 	struct stack_trace *trace = trace_data->trace;
2123e4196a5SMax Filippov 
2133e4196a5SMax Filippov 	if (trace_data->skip) {
2143e4196a5SMax Filippov 		--trace_data->skip;
2153e4196a5SMax Filippov 		return 0;
2163e4196a5SMax Filippov 	}
2173e4196a5SMax Filippov 	if (!kernel_text_address(frame->pc))
2183e4196a5SMax Filippov 		return 0;
2193e4196a5SMax Filippov 
2203e4196a5SMax Filippov 	trace->entries[trace->nr_entries++] = frame->pc;
2213e4196a5SMax Filippov 	return trace->nr_entries >= trace->max_entries;
2223e4196a5SMax Filippov }
2233e4196a5SMax Filippov 
save_stack_trace_tsk(struct task_struct * task,struct stack_trace * trace)2243e4196a5SMax Filippov void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace)
2253e4196a5SMax Filippov {
2263e4196a5SMax Filippov 	struct stack_trace_data trace_data = {
2273e4196a5SMax Filippov 		.trace = trace,
2283e4196a5SMax Filippov 		.skip = trace->skip,
2293e4196a5SMax Filippov 	};
2303e4196a5SMax Filippov 	walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data);
2313e4196a5SMax Filippov }
2323e4196a5SMax Filippov EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
2333e4196a5SMax Filippov 
save_stack_trace(struct stack_trace * trace)2343e4196a5SMax Filippov void save_stack_trace(struct stack_trace *trace)
2353e4196a5SMax Filippov {
2363e4196a5SMax Filippov 	save_stack_trace_tsk(current, trace);
2373e4196a5SMax Filippov }
2383e4196a5SMax Filippov EXPORT_SYMBOL_GPL(save_stack_trace);
2393e4196a5SMax Filippov 
2403e4196a5SMax Filippov #endif
2413ae908c9SMax Filippov 
2423ae908c9SMax Filippov struct return_addr_data {
2433ae908c9SMax Filippov 	unsigned long addr;
2443ae908c9SMax Filippov 	unsigned skip;
2453ae908c9SMax Filippov };
2463ae908c9SMax Filippov 
return_address_cb(struct stackframe * frame,void * data)2473ae908c9SMax Filippov static int return_address_cb(struct stackframe *frame, void *data)
2483ae908c9SMax Filippov {
2493ae908c9SMax Filippov 	struct return_addr_data *r = data;
2503ae908c9SMax Filippov 
2513ae908c9SMax Filippov 	if (r->skip) {
2523ae908c9SMax Filippov 		--r->skip;
2533ae908c9SMax Filippov 		return 0;
2543ae908c9SMax Filippov 	}
2553ae908c9SMax Filippov 	if (!kernel_text_address(frame->pc))
2563ae908c9SMax Filippov 		return 0;
2573ae908c9SMax Filippov 	r->addr = frame->pc;
2583ae908c9SMax Filippov 	return 1;
2593ae908c9SMax Filippov }
2603ae908c9SMax Filippov 
261ada770b1SMax Filippov /*
262ada770b1SMax Filippov  * level == 0 is for the return address from the caller of this function,
263ada770b1SMax Filippov  * not from this function itself.
264ada770b1SMax Filippov  */
return_address(unsigned level)2653ae908c9SMax Filippov unsigned long return_address(unsigned level)
2663ae908c9SMax Filippov {
2673ae908c9SMax Filippov 	struct return_addr_data r = {
268ada770b1SMax Filippov 		.skip = level,
2693ae908c9SMax Filippov 	};
2703ae908c9SMax Filippov 	walk_stackframe(stack_pointer(NULL), return_address_cb, &r);
2713ae908c9SMax Filippov 	return r.addr;
2723ae908c9SMax Filippov }
2733ae908c9SMax Filippov EXPORT_SYMBOL(return_address);
274