| 1 | |
| 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 | }
|