xref: /linux-6.15/arch/sh/kernel/dumpstack.c (revision c0735ae9)
15933f6d2SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
24e14dfc7SMatt Fleming /*
34e14dfc7SMatt Fleming  *  Copyright (C) 1991, 1992  Linus Torvalds
44e14dfc7SMatt Fleming  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
54e14dfc7SMatt Fleming  *  Copyright (C) 2009  Matt Fleming
649453264SPaul Mundt  *  Copyright (C) 2002 - 2012  Paul Mundt
74e14dfc7SMatt Fleming  */
84e14dfc7SMatt Fleming #include <linux/kallsyms.h>
94e14dfc7SMatt Fleming #include <linux/ftrace.h>
104e14dfc7SMatt Fleming #include <linux/debug_locks.h>
11b17b0153SIngo Molnar #include <linux/sched/debug.h>
1268db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
1349453264SPaul Mundt #include <linux/kdebug.h>
1449453264SPaul Mundt #include <linux/export.h>
1549453264SPaul Mundt #include <linux/uaccess.h>
160eff9f66SMatt Fleming #include <asm/unwinder.h>
174e14dfc7SMatt Fleming #include <asm/stacktrace.h>
184e14dfc7SMatt Fleming 
dump_mem(const char * str,const char * loglvl,unsigned long bottom,unsigned long top)19*0632a6d8SGeert Uytterhoeven void dump_mem(const char *str, const char *loglvl, unsigned long bottom,
20*0632a6d8SGeert Uytterhoeven 	      unsigned long top)
2149453264SPaul Mundt {
2249453264SPaul Mundt 	unsigned long p;
2349453264SPaul Mundt 	int i;
2449453264SPaul Mundt 
25ebf0a36aSDmitry Safonov 	printk("%s%s(0x%08lx to 0x%08lx)\n", loglvl, str, bottom, top);
2649453264SPaul Mundt 
2749453264SPaul Mundt 	for (p = bottom & ~31; p < top; ) {
28ebf0a36aSDmitry Safonov 		printk("%s%04lx: ", loglvl,  p & 0xffff);
2949453264SPaul Mundt 
3049453264SPaul Mundt 		for (i = 0; i < 8; i++, p += 4) {
3149453264SPaul Mundt 			unsigned int val;
3249453264SPaul Mundt 
3349453264SPaul Mundt 			if (p < bottom || p >= top)
34*0632a6d8SGeert Uytterhoeven 				pr_cont("         ");
3549453264SPaul Mundt 			else {
3649453264SPaul Mundt 				if (__get_user(val, (unsigned int __user *)p)) {
37*0632a6d8SGeert Uytterhoeven 					pr_cont("\n");
3849453264SPaul Mundt 					return;
3949453264SPaul Mundt 				}
40*0632a6d8SGeert Uytterhoeven 				pr_cont("%08x ", val);
4149453264SPaul Mundt 			}
4249453264SPaul Mundt 		}
43*0632a6d8SGeert Uytterhoeven 		pr_cont("\n");
4449453264SPaul Mundt 	}
4549453264SPaul Mundt }
4649453264SPaul Mundt 
printk_address(unsigned long address,int reliable)47fd722f25SGeert Uytterhoeven void printk_address(unsigned long address, int reliable)
484e14dfc7SMatt Fleming {
49*0632a6d8SGeert Uytterhoeven 	pr_cont(" [<%px>] %s%pS\n", (void *) address,
504e14dfc7SMatt Fleming 		reliable ? "" : "? ", (void *) address);
514e14dfc7SMatt Fleming }
524e14dfc7SMatt Fleming 
534e14dfc7SMatt Fleming #ifdef CONFIG_FUNCTION_GRAPH_TRACER
544e14dfc7SMatt Fleming static void
print_ftrace_graph_addr(unsigned long addr,void * data,const struct stacktrace_ops * ops,struct thread_info * tinfo,int * graph)554e14dfc7SMatt Fleming print_ftrace_graph_addr(unsigned long addr, void *data,
564e14dfc7SMatt Fleming 			const struct stacktrace_ops *ops,
574e14dfc7SMatt Fleming 			struct thread_info *tinfo, int *graph)
584e14dfc7SMatt Fleming {
594e14dfc7SMatt Fleming 	struct task_struct *task = tinfo->task;
60cec8d0e7SSteven Rostedt (VMware) 	struct ftrace_ret_stack *ret_stack;
614e14dfc7SMatt Fleming 	unsigned long ret_addr;
624e14dfc7SMatt Fleming 
634e14dfc7SMatt Fleming 	if (addr != (unsigned long)return_to_handler)
644e14dfc7SMatt Fleming 		return;
654e14dfc7SMatt Fleming 
66cec8d0e7SSteven Rostedt (VMware) 	if (!task->ret_stack)
674e14dfc7SMatt Fleming 		return;
684e14dfc7SMatt Fleming 
69cec8d0e7SSteven Rostedt (VMware) 	ret_stack = ftrace_graph_get_ret_stack(task, *graph);
70cec8d0e7SSteven Rostedt (VMware) 	if (!ret_stack)
71cec8d0e7SSteven Rostedt (VMware) 		return;
72cec8d0e7SSteven Rostedt (VMware) 
73cec8d0e7SSteven Rostedt (VMware) 	ret_addr = ret_stack->ret;
744e14dfc7SMatt Fleming 
754e14dfc7SMatt Fleming 	ops->address(data, ret_addr, 1);
764e14dfc7SMatt Fleming 
774e14dfc7SMatt Fleming 	(*graph)++;
784e14dfc7SMatt Fleming }
794e14dfc7SMatt Fleming #else
804e14dfc7SMatt Fleming static inline void
print_ftrace_graph_addr(unsigned long addr,void * data,const struct stacktrace_ops * ops,struct thread_info * tinfo,int * graph)814e14dfc7SMatt Fleming print_ftrace_graph_addr(unsigned long addr, void *data,
824e14dfc7SMatt Fleming 			const struct stacktrace_ops *ops,
834e14dfc7SMatt Fleming 			struct thread_info *tinfo, int *graph)
844e14dfc7SMatt Fleming { }
854e14dfc7SMatt Fleming #endif
864e14dfc7SMatt Fleming 
870eff9f66SMatt Fleming void
stack_reader_dump(struct task_struct * task,struct pt_regs * regs,unsigned long * sp,const struct stacktrace_ops * ops,void * data)880eff9f66SMatt Fleming stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
894e14dfc7SMatt Fleming 		  unsigned long *sp, const struct stacktrace_ops *ops,
904e14dfc7SMatt Fleming 		  void *data)
914e14dfc7SMatt Fleming {
924e14dfc7SMatt Fleming 	struct thread_info *context;
934e14dfc7SMatt Fleming 	int graph = 0;
944e14dfc7SMatt Fleming 
954e14dfc7SMatt Fleming 	context = (struct thread_info *)
964e14dfc7SMatt Fleming 		((unsigned long)sp & (~(THREAD_SIZE - 1)));
974e14dfc7SMatt Fleming 
984e14dfc7SMatt Fleming 	while (!kstack_end(sp)) {
994e14dfc7SMatt Fleming 		unsigned long addr = *sp++;
1004e14dfc7SMatt Fleming 
1014e14dfc7SMatt Fleming 		if (__kernel_text_address(addr)) {
102f9967e23SPaul Mundt 			ops->address(data, addr, 1);
1034e14dfc7SMatt Fleming 
1044e14dfc7SMatt Fleming 			print_ftrace_graph_addr(addr, data, ops,
1054e14dfc7SMatt Fleming 						context, &graph);
1064e14dfc7SMatt Fleming 		}
1074e14dfc7SMatt Fleming 	}
1084e14dfc7SMatt Fleming }
1094e14dfc7SMatt Fleming 
1104e14dfc7SMatt Fleming /*
1114e14dfc7SMatt Fleming  * Print one address/symbol entries per line.
1124e14dfc7SMatt Fleming  */
print_trace_address(void * data,unsigned long addr,int reliable)1134e14dfc7SMatt Fleming static void print_trace_address(void *data, unsigned long addr, int reliable)
1144e14dfc7SMatt Fleming {
115f6bed866SGeert Uytterhoeven 	printk("%s", (char *)data);
116fd722f25SGeert Uytterhoeven 	printk_address(addr, reliable);
1174e14dfc7SMatt Fleming }
1184e14dfc7SMatt Fleming 
1194e14dfc7SMatt Fleming static const struct stacktrace_ops print_trace_ops = {
1204e14dfc7SMatt Fleming 	.address = print_trace_address,
1214e14dfc7SMatt Fleming };
1224e14dfc7SMatt Fleming 
show_trace(struct task_struct * tsk,unsigned long * sp,struct pt_regs * regs,const char * loglvl)1234e14dfc7SMatt Fleming void show_trace(struct task_struct *tsk, unsigned long *sp,
124539e786cSDmitry Safonov 		struct pt_regs *regs, const char *loglvl)
1254e14dfc7SMatt Fleming {
1264e14dfc7SMatt Fleming 	if (regs && user_mode(regs))
1274e14dfc7SMatt Fleming 		return;
1284e14dfc7SMatt Fleming 
129539e786cSDmitry Safonov 	printk("%s\nCall trace:\n", loglvl);
1304e14dfc7SMatt Fleming 
131539e786cSDmitry Safonov 	unwind_stack(tsk, regs, sp, &print_trace_ops, (void *)loglvl);
1324e14dfc7SMatt Fleming 
133*0632a6d8SGeert Uytterhoeven 	pr_cont("\n");
1344e14dfc7SMatt Fleming 
1354e14dfc7SMatt Fleming 	if (!tsk)
1364e14dfc7SMatt Fleming 		tsk = current;
1374e14dfc7SMatt Fleming 
1384e14dfc7SMatt Fleming 	debug_show_held_locks(tsk);
1394e14dfc7SMatt Fleming }
14049453264SPaul Mundt 
show_stack(struct task_struct * tsk,unsigned long * sp,const char * loglvl)1419cb8f069SDmitry Safonov void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
14249453264SPaul Mundt {
14349453264SPaul Mundt 	unsigned long stack;
14449453264SPaul Mundt 
14549453264SPaul Mundt 	if (!tsk)
14649453264SPaul Mundt 		tsk = current;
14749453264SPaul Mundt 	if (tsk == current)
14849453264SPaul Mundt 		sp = (unsigned long *)current_stack_pointer;
14949453264SPaul Mundt 	else
15049453264SPaul Mundt 		sp = (unsigned long *)tsk->thread.sp;
15149453264SPaul Mundt 
15249453264SPaul Mundt 	stack = (unsigned long)sp;
153e6e371c4SDmitry Safonov 	dump_mem("Stack: ", loglvl, stack, THREAD_SIZE +
15449453264SPaul Mundt 		 (unsigned long)task_stack_page(tsk));
155e6e371c4SDmitry Safonov 	show_trace(tsk, sp, NULL, loglvl);
156e6e371c4SDmitry Safonov }
157