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