xref: /linux/arch/alpha/kernel/stacktrace.c (revision ca58a3dde621067333f481547db4afc587d7708a)
1*46651c65SMagnus Lindholm // SPDX-License-Identifier: GPL-2.0
2*46651c65SMagnus Lindholm #include <linux/sched.h>
3*46651c65SMagnus Lindholm #include <linux/sched/task_stack.h>
4*46651c65SMagnus Lindholm #include <linux/stacktrace.h>
5*46651c65SMagnus Lindholm #include <linux/kallsyms.h>
6*46651c65SMagnus Lindholm 
7*46651c65SMagnus Lindholm #include <asm/thread_info.h>
8*46651c65SMagnus Lindholm #include <asm/ptrace.h>
9*46651c65SMagnus Lindholm 
10*46651c65SMagnus Lindholm static __always_inline unsigned long alpha_get_current_ksp(void)
11*46651c65SMagnus Lindholm {
12*46651c65SMagnus Lindholm 	unsigned long sp;
13*46651c65SMagnus Lindholm 
14*46651c65SMagnus Lindholm 	asm volatile("mov $30, %0" : "=r"(sp));
15*46651c65SMagnus Lindholm 	return sp;
16*46651c65SMagnus Lindholm }
17*46651c65SMagnus Lindholm 
18*46651c65SMagnus Lindholm static void alpha_scan_kernel_stack(unsigned long ksp,
19*46651c65SMagnus Lindholm 				    stack_trace_consume_fn consume_entry,
20*46651c65SMagnus Lindholm 				    void *cookie)
21*46651c65SMagnus Lindholm {
22*46651c65SMagnus Lindholm 	unsigned long *p = (unsigned long *)ksp;
23*46651c65SMagnus Lindholm 
24*46651c65SMagnus Lindholm 	if (unlikely(ksp & (sizeof(unsigned long) - 1)))
25*46651c65SMagnus Lindholm 		return;
26*46651c65SMagnus Lindholm 
27*46651c65SMagnus Lindholm 	while (!kstack_end(p)) {
28*46651c65SMagnus Lindholm 		unsigned long addr = READ_ONCE_NOCHECK(*p++);
29*46651c65SMagnus Lindholm 
30*46651c65SMagnus Lindholm 		if (!__kernel_text_address(addr))
31*46651c65SMagnus Lindholm 			continue;
32*46651c65SMagnus Lindholm 
33*46651c65SMagnus Lindholm 		if (!consume_entry(cookie, addr))
34*46651c65SMagnus Lindholm 			break;
35*46651c65SMagnus Lindholm 	}
36*46651c65SMagnus Lindholm }
37*46651c65SMagnus Lindholm 
38*46651c65SMagnus Lindholm noinline void arch_stack_walk(stack_trace_consume_fn consume_entry,
39*46651c65SMagnus Lindholm 				      void *cookie,
40*46651c65SMagnus Lindholm 				      struct task_struct *task,
41*46651c65SMagnus Lindholm 				      struct pt_regs *regs)
42*46651c65SMagnus Lindholm {
43*46651c65SMagnus Lindholm 	unsigned long ksp;
44*46651c65SMagnus Lindholm 
45*46651c65SMagnus Lindholm 	if (!task)
46*46651c65SMagnus Lindholm 		task = current;
47*46651c65SMagnus Lindholm 
48*46651c65SMagnus Lindholm 	if (regs && task == current) {
49*46651c65SMagnus Lindholm 		/*
50*46651c65SMagnus Lindholm 		 * pt_regs is stored on the kernel stack; regs+1 matches
51*46651c65SMagnus Lindholm 		 * what arch/alpha/kernel/traps.c uses as the trace start.
52*46651c65SMagnus Lindholm 		 */
53*46651c65SMagnus Lindholm 		ksp = (unsigned long)(regs + 1);
54*46651c65SMagnus Lindholm 	} else if (task == current) {
55*46651c65SMagnus Lindholm 		ksp = alpha_get_current_ksp();
56*46651c65SMagnus Lindholm 	} else {
57*46651c65SMagnus Lindholm 		ksp = task_thread_info(task)->pcb.ksp;
58*46651c65SMagnus Lindholm 	}
59*46651c65SMagnus Lindholm 
60*46651c65SMagnus Lindholm 	alpha_scan_kernel_stack(ksp, consume_entry, cookie);
61*46651c65SMagnus Lindholm }
62