xref: /openbmc/linux/arch/mips/kernel/stacktrace.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21df0f0ffSAtsushi Nemoto /*
31df0f0ffSAtsushi Nemoto  * Stack trace management functions
41df0f0ffSAtsushi Nemoto  *
51df0f0ffSAtsushi Nemoto  *  Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
61df0f0ffSAtsushi Nemoto  */
71df0f0ffSAtsushi Nemoto #include <linux/sched.h>
8b17b0153SIngo Molnar #include <linux/sched/debug.h>
968db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
101df0f0ffSAtsushi Nemoto #include <linux/stacktrace.h>
1173bc256dSPaul Gortmaker #include <linux/export.h>
121df0f0ffSAtsushi Nemoto #include <asm/stacktrace.h>
131df0f0ffSAtsushi Nemoto 
141df0f0ffSAtsushi Nemoto /*
151df0f0ffSAtsushi Nemoto  * Save stack-backtrace addresses into a stack_trace buffer:
161df0f0ffSAtsushi Nemoto  */
save_raw_context_stack(struct stack_trace * trace,unsigned long reg29,int savesched)171df0f0ffSAtsushi Nemoto static void save_raw_context_stack(struct stack_trace *trace,
18e1e16115SAaro Koskinen 	unsigned long reg29, int savesched)
191df0f0ffSAtsushi Nemoto {
201df0f0ffSAtsushi Nemoto 	unsigned long *sp = (unsigned long *)reg29;
211df0f0ffSAtsushi Nemoto 	unsigned long addr;
221df0f0ffSAtsushi Nemoto 
231df0f0ffSAtsushi Nemoto 	while (!kstack_end(sp)) {
241df0f0ffSAtsushi Nemoto 		addr = *sp++;
25e1e16115SAaro Koskinen 		if (__kernel_text_address(addr) &&
26e1e16115SAaro Koskinen 		    (savesched || !in_sched_functions(addr))) {
2723126692SAtsushi Nemoto 			if (trace->skip > 0)
2823126692SAtsushi Nemoto 				trace->skip--;
291df0f0ffSAtsushi Nemoto 			else
3023126692SAtsushi Nemoto 				trace->entries[trace->nr_entries++] = addr;
311df0f0ffSAtsushi Nemoto 			if (trace->nr_entries >= trace->max_entries)
321df0f0ffSAtsushi Nemoto 				break;
331df0f0ffSAtsushi Nemoto 		}
341df0f0ffSAtsushi Nemoto 	}
351df0f0ffSAtsushi Nemoto }
361df0f0ffSAtsushi Nemoto 
save_context_stack(struct stack_trace * trace,struct task_struct * tsk,struct pt_regs * regs,int savesched)372ec220e2SKen Chen static void save_context_stack(struct stack_trace *trace,
38e1e16115SAaro Koskinen 	struct task_struct *tsk, struct pt_regs *regs, int savesched)
391df0f0ffSAtsushi Nemoto {
401df0f0ffSAtsushi Nemoto 	unsigned long sp = regs->regs[29];
411df0f0ffSAtsushi Nemoto #ifdef CONFIG_KALLSYMS
421df0f0ffSAtsushi Nemoto 	unsigned long ra = regs->regs[31];
431df0f0ffSAtsushi Nemoto 	unsigned long pc = regs->cp0_epc;
441df0f0ffSAtsushi Nemoto 
451df0f0ffSAtsushi Nemoto 	if (raw_show_trace || !__kernel_text_address(pc)) {
461924600cSAtsushi Nemoto 		unsigned long stack_page =
472ec220e2SKen Chen 			(unsigned long)task_stack_page(tsk);
4823126692SAtsushi Nemoto 		if (stack_page && sp >= stack_page &&
4923126692SAtsushi Nemoto 		    sp <= stack_page + THREAD_SIZE - 32)
50e1e16115SAaro Koskinen 			save_raw_context_stack(trace, sp, savesched);
511924600cSAtsushi Nemoto 		return;
521df0f0ffSAtsushi Nemoto 	}
531df0f0ffSAtsushi Nemoto 	do {
54e1e16115SAaro Koskinen 		if (savesched || !in_sched_functions(pc)) {
5523126692SAtsushi Nemoto 			if (trace->skip > 0)
5623126692SAtsushi Nemoto 				trace->skip--;
571df0f0ffSAtsushi Nemoto 			else
5823126692SAtsushi Nemoto 				trace->entries[trace->nr_entries++] = pc;
591df0f0ffSAtsushi Nemoto 			if (trace->nr_entries >= trace->max_entries)
601df0f0ffSAtsushi Nemoto 				break;
61e1e16115SAaro Koskinen 		}
622ec220e2SKen Chen 		pc = unwind_stack(tsk, &sp, pc, &ra);
631df0f0ffSAtsushi Nemoto 	} while (pc);
641df0f0ffSAtsushi Nemoto #else
65e1e16115SAaro Koskinen 	save_raw_context_stack(trace, sp, savesched);
661df0f0ffSAtsushi Nemoto #endif
671df0f0ffSAtsushi Nemoto }
681df0f0ffSAtsushi Nemoto 
691df0f0ffSAtsushi Nemoto /*
701df0f0ffSAtsushi Nemoto  * Save stack-backtrace addresses into a stack_trace buffer.
711df0f0ffSAtsushi Nemoto  */
save_stack_trace(struct stack_trace * trace)72ab1b6f03SChristoph Hellwig void save_stack_trace(struct stack_trace *trace)
731df0f0ffSAtsushi Nemoto {
742ec220e2SKen Chen 	save_stack_trace_tsk(current, trace);
752ec220e2SKen Chen }
762ec220e2SKen Chen EXPORT_SYMBOL_GPL(save_stack_trace);
772ec220e2SKen Chen 
save_stack_trace_tsk(struct task_struct * tsk,struct stack_trace * trace)782ec220e2SKen Chen void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
792ec220e2SKen Chen {
801df0f0ffSAtsushi Nemoto 	struct pt_regs dummyregs;
811df0f0ffSAtsushi Nemoto 	struct pt_regs *regs = &dummyregs;
821df0f0ffSAtsushi Nemoto 
831df0f0ffSAtsushi Nemoto 	WARN_ON(trace->nr_entries || !trace->max_entries);
841df0f0ffSAtsushi Nemoto 
852ec220e2SKen Chen 	if (tsk != current) {
862ec220e2SKen Chen 		regs->regs[29] = tsk->thread.reg29;
872ec220e2SKen Chen 		regs->regs[31] = 0;
882ec220e2SKen Chen 		regs->cp0_epc = tsk->thread.reg31;
892ec220e2SKen Chen 	} else
901df0f0ffSAtsushi Nemoto 		prepare_frametrace(regs);
91e1e16115SAaro Koskinen 	save_context_stack(trace, tsk, regs, tsk == current);
921df0f0ffSAtsushi Nemoto }
932ec220e2SKen Chen EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
94