1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2008 ARM Limited
4 * Copyright (C) 2014 Regents of the University of California
7 #include <linux/export.h>
8 #include <linux/kallsyms.h>
9 #include <linux/sched.h>
10 #include <linux/sched/debug.h>
11 #include <linux/sched/task_stack.h>
12 #include <linux/stacktrace.h>
13 #include <linux/ftrace.h>
15 #include <asm/stacktrace.h>
17 #ifdef CONFIG_FRAME_POINTER
19 extern asmlinkage
void handle_exception(void);
21 static inline int fp_is_valid(unsigned long fp
, unsigned long sp
)
23 unsigned long low
, high
;
25 low
= sp
+ sizeof(struct stackframe
);
26 high
= ALIGN(sp
, THREAD_SIZE
);
28 return !(fp
< low
|| fp
> high
|| fp
& 0x07);
31 void notrace
walk_stackframe(struct task_struct
*task
, struct pt_regs
*regs
,
32 bool (*fn
)(void *, unsigned long), void *arg
)
34 unsigned long fp
, sp
, pc
;
39 fp
= frame_pointer(regs
);
40 sp
= user_stack_pointer(regs
);
41 pc
= instruction_pointer(regs
);
42 } else if (task
== NULL
|| task
== current
) {
43 fp
= (unsigned long)__builtin_frame_address(0);
44 sp
= current_stack_pointer
;
45 pc
= (unsigned long)walk_stackframe
;
48 /* task blocked in __switch_to */
49 fp
= task
->thread
.s
[0];
55 struct stackframe
*frame
;
57 if (unlikely(!__kernel_text_address(pc
) || (level
++ >= 0 && !fn(arg
, pc
))))
60 if (unlikely(!fp_is_valid(fp
, sp
)))
63 /* Unwind stack frame */
64 frame
= (struct stackframe
*)fp
- 1;
66 if (regs
&& (regs
->epc
== pc
) && fp_is_valid(frame
->ra
, sp
)) {
67 /* We hit function where ra is not saved on the stack */
72 pc
= ftrace_graph_ret_addr(current
, &graph_idx
, frame
->ra
,
74 if (pc
== (unsigned long)handle_exception
) {
75 if (unlikely(!__kernel_text_address(pc
) || !fn(arg
, pc
)))
78 pc
= ((struct pt_regs
*)sp
)->epc
;
79 fp
= ((struct pt_regs
*)sp
)->s0
;
86 #else /* !CONFIG_FRAME_POINTER */
88 void notrace
walk_stackframe(struct task_struct
*task
,
89 struct pt_regs
*regs
, bool (*fn
)(void *, unsigned long), void *arg
)
95 sp
= user_stack_pointer(regs
);
96 pc
= instruction_pointer(regs
);
97 } else if (task
== NULL
|| task
== current
) {
98 sp
= current_stack_pointer
;
99 pc
= (unsigned long)walk_stackframe
;
101 /* task blocked in __switch_to */
102 sp
= task
->thread
.sp
;
103 pc
= task
->thread
.ra
;
106 if (unlikely(sp
& 0x7))
109 ksp
= (unsigned long *)sp
;
110 while (!kstack_end(ksp
)) {
111 if (__kernel_text_address(pc
) && unlikely(!fn(arg
, pc
)))
113 pc
= READ_ONCE_NOCHECK(*ksp
++) - 0x4;
117 #endif /* CONFIG_FRAME_POINTER */
119 static bool print_trace_address(void *arg
, unsigned long pc
)
121 const char *loglvl
= arg
;
123 print_ip_sym(loglvl
, pc
);
127 noinline
void dump_backtrace(struct pt_regs
*regs
, struct task_struct
*task
,
130 walk_stackframe(task
, regs
, print_trace_address
, (void *)loglvl
);
133 void show_stack(struct task_struct
*task
, unsigned long *sp
, const char *loglvl
)
135 pr_cont("%sCall Trace:\n", loglvl
);
136 dump_backtrace(NULL
, task
, loglvl
);
139 static bool save_wchan(void *arg
, unsigned long pc
)
141 if (!in_sched_functions(pc
)) {
142 unsigned long *p
= arg
;
149 unsigned long __get_wchan(struct task_struct
*task
)
151 unsigned long pc
= 0;
153 if (!try_get_task_stack(task
))
155 walk_stackframe(task
, NULL
, save_wchan
, &pc
);
156 put_task_stack(task
);
160 noinline noinstr
void arch_stack_walk(stack_trace_consume_fn consume_entry
, void *cookie
,
161 struct task_struct
*task
, struct pt_regs
*regs
)
163 walk_stackframe(task
, regs
, consume_entry
, cookie
);
167 * Get the return address for a single stackframe and return a pointer to the
170 static unsigned long unwind_user_frame(stack_trace_consume_fn consume_entry
,
171 void *cookie
, unsigned long fp
,
172 unsigned long reg_ra
)
174 struct stackframe buftail
;
175 unsigned long ra
= 0;
176 unsigned long __user
*user_frame_tail
=
177 (unsigned long __user
*)(fp
- sizeof(struct stackframe
));
179 /* Check accessibility of one struct frame_tail beyond */
180 if (!access_ok(user_frame_tail
, sizeof(buftail
)))
182 if (__copy_from_user_inatomic(&buftail
, user_frame_tail
,
186 ra
= reg_ra
? : buftail
.ra
;
189 if (!ra
|| !consume_entry(cookie
, ra
))
195 void arch_stack_walk_user(stack_trace_consume_fn consume_entry
, void *cookie
,
196 const struct pt_regs
*regs
)
198 unsigned long fp
= 0;
201 if (!consume_entry(cookie
, regs
->epc
))
204 fp
= unwind_user_frame(consume_entry
, cookie
, fp
, regs
->ra
);
205 while (fp
&& !(fp
& 0x7))
206 fp
= unwind_user_frame(consume_entry
, cookie
, fp
, 0);