xref: /openbmc/linux/arch/xtensa/kernel/stacktrace.c (revision 7c0f6ba6)
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 
153e4196a5SMax Filippov #include <asm/stacktrace.h>
163e4196a5SMax Filippov #include <asm/traps.h>
177c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
185fdf377dSMax Filippov 
195fdf377dSMax Filippov #if IS_ENABLED(CONFIG_OPROFILE) || IS_ENABLED(CONFIG_PERF_EVENTS)
205fdf377dSMax Filippov 
215fdf377dSMax Filippov /* Address of common_exception_return, used to check the
225fdf377dSMax Filippov  * transition from kernel to user space.
235fdf377dSMax Filippov  */
245fdf377dSMax Filippov extern int common_exception_return;
255fdf377dSMax Filippov 
265fdf377dSMax Filippov /* A struct that maps to the part of the frame containing the a0 and
275fdf377dSMax Filippov  * a1 registers.
285fdf377dSMax Filippov  */
295fdf377dSMax Filippov struct frame_start {
305fdf377dSMax Filippov 	unsigned long a0;
315fdf377dSMax Filippov 	unsigned long a1;
325fdf377dSMax Filippov };
335fdf377dSMax Filippov 
345fdf377dSMax Filippov void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
355fdf377dSMax Filippov 			   int (*ufn)(struct stackframe *frame, void *data),
365fdf377dSMax Filippov 			   void *data)
375fdf377dSMax Filippov {
385fdf377dSMax Filippov 	unsigned long windowstart = regs->windowstart;
395fdf377dSMax Filippov 	unsigned long windowbase = regs->windowbase;
405fdf377dSMax Filippov 	unsigned long a0 = regs->areg[0];
415fdf377dSMax Filippov 	unsigned long a1 = regs->areg[1];
425fdf377dSMax Filippov 	unsigned long pc = regs->pc;
435fdf377dSMax Filippov 	struct stackframe frame;
445fdf377dSMax Filippov 	int index;
455fdf377dSMax Filippov 
465fdf377dSMax Filippov 	if (!depth--)
475fdf377dSMax Filippov 		return;
485fdf377dSMax Filippov 
495fdf377dSMax Filippov 	frame.pc = pc;
505fdf377dSMax Filippov 	frame.sp = a1;
515fdf377dSMax Filippov 
525fdf377dSMax Filippov 	if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
535fdf377dSMax Filippov 		return;
545fdf377dSMax Filippov 
555fdf377dSMax Filippov 	/* Two steps:
565fdf377dSMax Filippov 	 *
575fdf377dSMax Filippov 	 * 1. Look through the register window for the
585fdf377dSMax Filippov 	 * previous PCs in the call trace.
595fdf377dSMax Filippov 	 *
605fdf377dSMax Filippov 	 * 2. Look on the stack.
615fdf377dSMax Filippov 	 */
625fdf377dSMax Filippov 
635fdf377dSMax Filippov 	/* Step 1.  */
645fdf377dSMax Filippov 	/* Rotate WINDOWSTART to move the bit corresponding to
655fdf377dSMax Filippov 	 * the current window to the bit #0.
665fdf377dSMax Filippov 	 */
675fdf377dSMax Filippov 	windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
685fdf377dSMax Filippov 
695fdf377dSMax Filippov 	/* Look for bits that are set, they correspond to
705fdf377dSMax Filippov 	 * valid windows.
715fdf377dSMax Filippov 	 */
725fdf377dSMax Filippov 	for (index = WSBITS - 1; (index > 0) && depth; depth--, index--)
735fdf377dSMax Filippov 		if (windowstart & (1 << index)) {
745fdf377dSMax Filippov 			/* Get the PC from a0 and a1. */
755fdf377dSMax Filippov 			pc = MAKE_PC_FROM_RA(a0, pc);
765fdf377dSMax Filippov 			/* Read a0 and a1 from the
775fdf377dSMax Filippov 			 * corresponding position in AREGs.
785fdf377dSMax Filippov 			 */
795fdf377dSMax Filippov 			a0 = regs->areg[index * 4];
805fdf377dSMax Filippov 			a1 = regs->areg[index * 4 + 1];
815fdf377dSMax Filippov 
825fdf377dSMax Filippov 			frame.pc = pc;
835fdf377dSMax Filippov 			frame.sp = a1;
845fdf377dSMax Filippov 
855fdf377dSMax Filippov 			if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
865fdf377dSMax Filippov 				return;
875fdf377dSMax Filippov 		}
885fdf377dSMax Filippov 
895fdf377dSMax Filippov 	/* Step 2. */
905fdf377dSMax Filippov 	/* We are done with the register window, we need to
915fdf377dSMax Filippov 	 * look through the stack.
925fdf377dSMax Filippov 	 */
935fdf377dSMax Filippov 	if (!depth)
945fdf377dSMax Filippov 		return;
955fdf377dSMax Filippov 
965fdf377dSMax Filippov 	/* Start from the a1 register. */
975fdf377dSMax Filippov 	/* a1 = regs->areg[1]; */
985fdf377dSMax Filippov 	while (a0 != 0 && depth--) {
995fdf377dSMax Filippov 		struct frame_start frame_start;
1005fdf377dSMax Filippov 		/* Get the location for a1, a0 for the
1015fdf377dSMax Filippov 		 * previous frame from the current a1.
1025fdf377dSMax Filippov 		 */
1035fdf377dSMax Filippov 		unsigned long *psp = (unsigned long *)a1;
1045fdf377dSMax Filippov 
1055fdf377dSMax Filippov 		psp -= 4;
1065fdf377dSMax Filippov 
1075fdf377dSMax Filippov 		/* Check if the region is OK to access. */
1085fdf377dSMax Filippov 		if (!access_ok(VERIFY_READ, psp, sizeof(frame_start)))
1095fdf377dSMax Filippov 			return;
1105fdf377dSMax Filippov 		/* Copy a1, a0 from user space stack frame. */
1115fdf377dSMax Filippov 		if (__copy_from_user_inatomic(&frame_start, psp,
1125fdf377dSMax Filippov 					      sizeof(frame_start)))
1135fdf377dSMax Filippov 			return;
1145fdf377dSMax Filippov 
1155fdf377dSMax Filippov 		pc = MAKE_PC_FROM_RA(a0, pc);
1165fdf377dSMax Filippov 		a0 = frame_start.a0;
1175fdf377dSMax Filippov 		a1 = frame_start.a1;
1185fdf377dSMax Filippov 
1195fdf377dSMax Filippov 		frame.pc = pc;
1205fdf377dSMax Filippov 		frame.sp = a1;
1215fdf377dSMax Filippov 
1225fdf377dSMax Filippov 		if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
1235fdf377dSMax Filippov 			return;
1245fdf377dSMax Filippov 	}
1255fdf377dSMax Filippov }
1265fdf377dSMax Filippov EXPORT_SYMBOL(xtensa_backtrace_user);
1275fdf377dSMax Filippov 
1285fdf377dSMax Filippov void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
1295fdf377dSMax Filippov 			     int (*kfn)(struct stackframe *frame, void *data),
1305fdf377dSMax Filippov 			     int (*ufn)(struct stackframe *frame, void *data),
1315fdf377dSMax Filippov 			     void *data)
1325fdf377dSMax Filippov {
1335fdf377dSMax Filippov 	unsigned long pc = regs->depc > VALID_DOUBLE_EXCEPTION_ADDRESS ?
1345fdf377dSMax Filippov 		regs->depc : regs->pc;
1355fdf377dSMax Filippov 	unsigned long sp_start, sp_end;
1365fdf377dSMax Filippov 	unsigned long a0 = regs->areg[0];
1375fdf377dSMax Filippov 	unsigned long a1 = regs->areg[1];
1385fdf377dSMax Filippov 
1395fdf377dSMax Filippov 	sp_start = a1 & ~(THREAD_SIZE - 1);
1405fdf377dSMax Filippov 	sp_end = sp_start + THREAD_SIZE;
1415fdf377dSMax Filippov 
1425fdf377dSMax Filippov 	/* Spill the register window to the stack first. */
1435fdf377dSMax Filippov 	spill_registers();
1445fdf377dSMax Filippov 
1455fdf377dSMax Filippov 	/* Read the stack frames one by one and create the PC
1465fdf377dSMax Filippov 	 * from the a0 and a1 registers saved there.
1475fdf377dSMax Filippov 	 */
1485fdf377dSMax Filippov 	while (a1 > sp_start && a1 < sp_end && depth--) {
1495fdf377dSMax Filippov 		struct stackframe frame;
1505fdf377dSMax Filippov 		unsigned long *psp = (unsigned long *)a1;
1515fdf377dSMax Filippov 
1525fdf377dSMax Filippov 		frame.pc = pc;
1535fdf377dSMax Filippov 		frame.sp = a1;
1545fdf377dSMax Filippov 
1555fdf377dSMax Filippov 		if (kernel_text_address(pc) && kfn(&frame, data))
1565fdf377dSMax Filippov 			return;
1575fdf377dSMax Filippov 
1585fdf377dSMax Filippov 		if (pc == (unsigned long)&common_exception_return) {
1595fdf377dSMax Filippov 			regs = (struct pt_regs *)a1;
1605fdf377dSMax Filippov 			if (user_mode(regs)) {
1615fdf377dSMax Filippov 				if (ufn == NULL)
1625fdf377dSMax Filippov 					return;
1635fdf377dSMax Filippov 				xtensa_backtrace_user(regs, depth, ufn, data);
1645fdf377dSMax Filippov 				return;
1655fdf377dSMax Filippov 			}
1665fdf377dSMax Filippov 			a0 = regs->areg[0];
1675fdf377dSMax Filippov 			a1 = regs->areg[1];
1685fdf377dSMax Filippov 			continue;
1695fdf377dSMax Filippov 		}
1705fdf377dSMax Filippov 
1715fdf377dSMax Filippov 		sp_start = a1;
1725fdf377dSMax Filippov 
1735fdf377dSMax Filippov 		pc = MAKE_PC_FROM_RA(a0, pc);
1745fdf377dSMax Filippov 		a0 = *(psp - 4);
1755fdf377dSMax Filippov 		a1 = *(psp - 3);
1765fdf377dSMax Filippov 	}
1775fdf377dSMax Filippov }
1785fdf377dSMax Filippov EXPORT_SYMBOL(xtensa_backtrace_kernel);
1795fdf377dSMax Filippov 
1805fdf377dSMax Filippov #endif
1813e4196a5SMax Filippov 
1823e4196a5SMax Filippov void walk_stackframe(unsigned long *sp,
1833e4196a5SMax Filippov 		int (*fn)(struct stackframe *frame, void *data),
1843e4196a5SMax Filippov 		void *data)
1853e4196a5SMax Filippov {
1863e4196a5SMax Filippov 	unsigned long a0, a1;
1873e4196a5SMax Filippov 	unsigned long sp_end;
1883e4196a5SMax Filippov 
1893e4196a5SMax Filippov 	a1 = (unsigned long)sp;
1903e4196a5SMax Filippov 	sp_end = ALIGN(a1, THREAD_SIZE);
1913e4196a5SMax Filippov 
1923e4196a5SMax Filippov 	spill_registers();
1933e4196a5SMax Filippov 
1943e4196a5SMax Filippov 	while (a1 < sp_end) {
1953e4196a5SMax Filippov 		struct stackframe frame;
1963e4196a5SMax Filippov 
1973e4196a5SMax Filippov 		sp = (unsigned long *)a1;
1983e4196a5SMax Filippov 
1993e4196a5SMax Filippov 		a0 = *(sp - 4);
2003e4196a5SMax Filippov 		a1 = *(sp - 3);
2013e4196a5SMax Filippov 
2023e4196a5SMax Filippov 		if (a1 <= (unsigned long)sp)
2033e4196a5SMax Filippov 			break;
2043e4196a5SMax Filippov 
2053e4196a5SMax Filippov 		frame.pc = MAKE_PC_FROM_RA(a0, a1);
2063e4196a5SMax Filippov 		frame.sp = a1;
2073e4196a5SMax Filippov 
2083e4196a5SMax Filippov 		if (fn(&frame, data))
2093e4196a5SMax Filippov 			return;
2103e4196a5SMax Filippov 	}
2113e4196a5SMax Filippov }
2123e4196a5SMax Filippov 
2133e4196a5SMax Filippov #ifdef CONFIG_STACKTRACE
2143e4196a5SMax Filippov 
2153e4196a5SMax Filippov struct stack_trace_data {
2163e4196a5SMax Filippov 	struct stack_trace *trace;
2173e4196a5SMax Filippov 	unsigned skip;
2183e4196a5SMax Filippov };
2193e4196a5SMax Filippov 
2203e4196a5SMax Filippov static int stack_trace_cb(struct stackframe *frame, void *data)
2213e4196a5SMax Filippov {
2223e4196a5SMax Filippov 	struct stack_trace_data *trace_data = data;
2233e4196a5SMax Filippov 	struct stack_trace *trace = trace_data->trace;
2243e4196a5SMax Filippov 
2253e4196a5SMax Filippov 	if (trace_data->skip) {
2263e4196a5SMax Filippov 		--trace_data->skip;
2273e4196a5SMax Filippov 		return 0;
2283e4196a5SMax Filippov 	}
2293e4196a5SMax Filippov 	if (!kernel_text_address(frame->pc))
2303e4196a5SMax Filippov 		return 0;
2313e4196a5SMax Filippov 
2323e4196a5SMax Filippov 	trace->entries[trace->nr_entries++] = frame->pc;
2333e4196a5SMax Filippov 	return trace->nr_entries >= trace->max_entries;
2343e4196a5SMax Filippov }
2353e4196a5SMax Filippov 
2363e4196a5SMax Filippov void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace)
2373e4196a5SMax Filippov {
2383e4196a5SMax Filippov 	struct stack_trace_data trace_data = {
2393e4196a5SMax Filippov 		.trace = trace,
2403e4196a5SMax Filippov 		.skip = trace->skip,
2413e4196a5SMax Filippov 	};
2423e4196a5SMax Filippov 	walk_stackframe(stack_pointer(task), stack_trace_cb, &trace_data);
2433e4196a5SMax Filippov }
2443e4196a5SMax Filippov EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
2453e4196a5SMax Filippov 
2463e4196a5SMax Filippov void save_stack_trace(struct stack_trace *trace)
2473e4196a5SMax Filippov {
2483e4196a5SMax Filippov 	save_stack_trace_tsk(current, trace);
2493e4196a5SMax Filippov }
2503e4196a5SMax Filippov EXPORT_SYMBOL_GPL(save_stack_trace);
2513e4196a5SMax Filippov 
2523e4196a5SMax Filippov #endif
2533ae908c9SMax Filippov 
2543ae908c9SMax Filippov #ifdef CONFIG_FRAME_POINTER
2553ae908c9SMax Filippov 
2563ae908c9SMax Filippov struct return_addr_data {
2573ae908c9SMax Filippov 	unsigned long addr;
2583ae908c9SMax Filippov 	unsigned skip;
2593ae908c9SMax Filippov };
2603ae908c9SMax Filippov 
2613ae908c9SMax Filippov static int return_address_cb(struct stackframe *frame, void *data)
2623ae908c9SMax Filippov {
2633ae908c9SMax Filippov 	struct return_addr_data *r = data;
2643ae908c9SMax Filippov 
2653ae908c9SMax Filippov 	if (r->skip) {
2663ae908c9SMax Filippov 		--r->skip;
2673ae908c9SMax Filippov 		return 0;
2683ae908c9SMax Filippov 	}
2693ae908c9SMax Filippov 	if (!kernel_text_address(frame->pc))
2703ae908c9SMax Filippov 		return 0;
2713ae908c9SMax Filippov 	r->addr = frame->pc;
2723ae908c9SMax Filippov 	return 1;
2733ae908c9SMax Filippov }
2743ae908c9SMax Filippov 
2753ae908c9SMax Filippov unsigned long return_address(unsigned level)
2763ae908c9SMax Filippov {
2773ae908c9SMax Filippov 	struct return_addr_data r = {
2783ae908c9SMax Filippov 		.skip = level + 1,
2793ae908c9SMax Filippov 	};
2803ae908c9SMax Filippov 	walk_stackframe(stack_pointer(NULL), return_address_cb, &r);
2813ae908c9SMax Filippov 	return r.addr;
2823ae908c9SMax Filippov }
2833ae908c9SMax Filippov EXPORT_SYMBOL(return_address);
2843ae908c9SMax Filippov 
2853ae908c9SMax Filippov #endif
286