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