xref: /linux/arch/sh/kernel/dumpstack.c (revision 4494ce4fb4ff42946f48bbc8a5ac55ee18dca600)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Copyright (C) 1991, 1992  Linus Torvalds
4  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
5  *  Copyright (C) 2009  Matt Fleming
6  *  Copyright (C) 2002 - 2012  Paul Mundt
7  */
8 #include <linux/kallsyms.h>
9 #include <linux/ftrace.h>
10 #include <linux/debug_locks.h>
11 #include <linux/sched/debug.h>
12 #include <linux/sched/task_stack.h>
13 #include <linux/kdebug.h>
14 #include <linux/export.h>
15 #include <linux/uaccess.h>
16 #include <asm/unwinder.h>
17 #include <asm/stacktrace.h>
18 
19 void dump_mem(const char *str, unsigned long bottom, unsigned long top)
20 {
21 	unsigned long p;
22 	int i;
23 
24 	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
25 
26 	for (p = bottom & ~31; p < top; ) {
27 		printk("%04lx: ", p & 0xffff);
28 
29 		for (i = 0; i < 8; i++, p += 4) {
30 			unsigned int val;
31 
32 			if (p < bottom || p >= top)
33 				printk("         ");
34 			else {
35 				if (__get_user(val, (unsigned int __user *)p)) {
36 					printk("\n");
37 					return;
38 				}
39 				printk("%08x ", val);
40 			}
41 		}
42 		printk("\n");
43 	}
44 }
45 
46 void printk_address(unsigned long address, int reliable)
47 {
48 	printk(" [<%p>] %s%pS\n", (void *) address,
49 			reliable ? "" : "? ", (void *) address);
50 }
51 
52 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
53 static void
54 print_ftrace_graph_addr(unsigned long addr, void *data,
55 			const struct stacktrace_ops *ops,
56 			struct thread_info *tinfo, int *graph)
57 {
58 	struct task_struct *task = tinfo->task;
59 	unsigned long ret_addr;
60 	int index = task->curr_ret_stack;
61 
62 	if (addr != (unsigned long)return_to_handler)
63 		return;
64 
65 	if (!task->ret_stack || index < *graph)
66 		return;
67 
68 	index -= *graph;
69 	ret_addr = task->ret_stack[index].ret;
70 
71 	ops->address(data, ret_addr, 1);
72 
73 	(*graph)++;
74 }
75 #else
76 static inline void
77 print_ftrace_graph_addr(unsigned long addr, void *data,
78 			const struct stacktrace_ops *ops,
79 			struct thread_info *tinfo, int *graph)
80 { }
81 #endif
82 
83 void
84 stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
85 		  unsigned long *sp, const struct stacktrace_ops *ops,
86 		  void *data)
87 {
88 	struct thread_info *context;
89 	int graph = 0;
90 
91 	context = (struct thread_info *)
92 		((unsigned long)sp & (~(THREAD_SIZE - 1)));
93 
94 	while (!kstack_end(sp)) {
95 		unsigned long addr = *sp++;
96 
97 		if (__kernel_text_address(addr)) {
98 			ops->address(data, addr, 1);
99 
100 			print_ftrace_graph_addr(addr, data, ops,
101 						context, &graph);
102 		}
103 	}
104 }
105 
106 static int print_trace_stack(void *data, char *name)
107 {
108 	printk("%s <%s> ", (char *)data, name);
109 	return 0;
110 }
111 
112 /*
113  * Print one address/symbol entries per line.
114  */
115 static void print_trace_address(void *data, unsigned long addr, int reliable)
116 {
117 	printk("%s", (char *)data);
118 	printk_address(addr, reliable);
119 }
120 
121 static const struct stacktrace_ops print_trace_ops = {
122 	.stack = print_trace_stack,
123 	.address = print_trace_address,
124 };
125 
126 void show_trace(struct task_struct *tsk, unsigned long *sp,
127 		struct pt_regs *regs)
128 {
129 	if (regs && user_mode(regs))
130 		return;
131 
132 	printk("\nCall trace:\n");
133 
134 	unwind_stack(tsk, regs, sp, &print_trace_ops, "");
135 
136 	printk("\n");
137 
138 	if (!tsk)
139 		tsk = current;
140 
141 	debug_show_held_locks(tsk);
142 }
143 
144 void show_stack(struct task_struct *tsk, unsigned long *sp)
145 {
146 	unsigned long stack;
147 
148 	if (!tsk)
149 		tsk = current;
150 	if (tsk == current)
151 		sp = (unsigned long *)current_stack_pointer;
152 	else
153 		sp = (unsigned long *)tsk->thread.sp;
154 
155 	stack = (unsigned long)sp;
156 	dump_mem("Stack: ", stack, THREAD_SIZE +
157 		 (unsigned long)task_stack_page(tsk));
158 	show_trace(tsk, sp, NULL);
159 }
160