88#include <linux/efi.h>
99#include <linux/export.h>
1010#include <linux/ftrace.h>
11+ #include <linux/kprobes.h>
1112#include <linux/sched.h>
1213#include <linux/sched/debug.h>
1314#include <linux/sched/task_stack.h>
1819#include <asm/stack_pointer.h>
1920#include <asm/stacktrace.h>
2021
22+ /*
23+ * Kernel unwind state
24+ *
25+ * @common: Common unwind state.
26+ * @task: The task being unwound.
27+ * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance
28+ * associated with the most recently encountered replacement lr
29+ * value.
30+ */
31+ struct kunwind_state {
32+ struct unwind_state common ;
33+ struct task_struct * task ;
34+ #ifdef CONFIG_KRETPROBES
35+ struct llist_node * kr_cur ;
36+ #endif
37+ };
38+
39+ static __always_inline void
40+ kunwind_init (struct kunwind_state * state ,
41+ struct task_struct * task )
42+ {
43+ unwind_init_common (& state -> common );
44+ state -> task = task ;
45+ }
46+
2147/*
2248 * Start an unwind from a pt_regs.
2349 *
2652 * The regs must be on a stack currently owned by the calling task.
2753 */
2854static __always_inline void
29- unwind_init_from_regs (struct unwind_state * state ,
30- struct pt_regs * regs )
55+ kunwind_init_from_regs (struct kunwind_state * state ,
56+ struct pt_regs * regs )
3157{
32- unwind_init_common (state , current );
58+ kunwind_init (state , current );
3359
34- state -> fp = regs -> regs [29 ];
35- state -> pc = regs -> pc ;
60+ state -> common . fp = regs -> regs [29 ];
61+ state -> common . pc = regs -> pc ;
3662}
3763
3864/*
@@ -44,12 +70,12 @@ unwind_init_from_regs(struct unwind_state *state,
4470 * The function which invokes this must be noinline.
4571 */
4672static __always_inline void
47- unwind_init_from_caller (struct unwind_state * state )
73+ kunwind_init_from_caller (struct kunwind_state * state )
4874{
49- unwind_init_common (state , current );
75+ kunwind_init (state , current );
5076
51- state -> fp = (unsigned long )__builtin_frame_address (1 );
52- state -> pc = (unsigned long )__builtin_return_address (0 );
77+ state -> common . fp = (unsigned long )__builtin_frame_address (1 );
78+ state -> common . pc = (unsigned long )__builtin_return_address (0 );
5379}
5480
5581/*
@@ -63,35 +89,38 @@ unwind_init_from_caller(struct unwind_state *state)
6389 * call this for the current task.
6490 */
6591static __always_inline void
66- unwind_init_from_task (struct unwind_state * state ,
67- struct task_struct * task )
92+ kunwind_init_from_task (struct kunwind_state * state ,
93+ struct task_struct * task )
6894{
69- unwind_init_common (state , task );
95+ kunwind_init (state , task );
7096
71- state -> fp = thread_saved_fp (task );
72- state -> pc = thread_saved_pc (task );
97+ state -> common . fp = thread_saved_fp (task );
98+ state -> common . pc = thread_saved_pc (task );
7399}
74100
75101static __always_inline int
76- unwind_recover_return_address (struct unwind_state * state )
102+ kunwind_recover_return_address (struct kunwind_state * state )
77103{
78104#ifdef CONFIG_FUNCTION_GRAPH_TRACER
79105 if (state -> task -> ret_stack &&
80- (state -> pc == (unsigned long )return_to_handler )) {
106+ (state -> common . pc == (unsigned long )return_to_handler )) {
81107 unsigned long orig_pc ;
82- orig_pc = ftrace_graph_ret_addr (state -> task , NULL , state -> pc ,
83- (void * )state -> fp );
84- if (WARN_ON_ONCE (state -> pc == orig_pc ))
108+ orig_pc = ftrace_graph_ret_addr (state -> task , NULL ,
109+ state -> common .pc ,
110+ (void * )state -> common .fp );
111+ if (WARN_ON_ONCE (state -> common .pc == orig_pc ))
85112 return - EINVAL ;
86- state -> pc = orig_pc ;
113+ state -> common . pc = orig_pc ;
87114 }
88115#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
89116
90117#ifdef CONFIG_KRETPROBES
91- if (is_kretprobe_trampoline (state -> pc )) {
92- state -> pc = kretprobe_find_ret_addr (state -> task ,
93- (void * )state -> fp ,
94- & state -> kr_cur );
118+ if (is_kretprobe_trampoline (state -> common .pc )) {
119+ unsigned long orig_pc ;
120+ orig_pc = kretprobe_find_ret_addr (state -> task ,
121+ (void * )state -> common .fp ,
122+ & state -> kr_cur );
123+ state -> common .pc = orig_pc ;
95124 }
96125#endif /* CONFIG_KRETPROBES */
97126
@@ -106,38 +135,40 @@ unwind_recover_return_address(struct unwind_state *state)
106135 * and the location (but not the fp value) of B.
107136 */
108137static __always_inline int
109- unwind_next (struct unwind_state * state )
138+ kunwind_next (struct kunwind_state * state )
110139{
111140 struct task_struct * tsk = state -> task ;
112- unsigned long fp = state -> fp ;
141+ unsigned long fp = state -> common . fp ;
113142 int err ;
114143
115144 /* Final frame; nothing to unwind */
116145 if (fp == (unsigned long )task_pt_regs (tsk )-> stackframe )
117146 return - ENOENT ;
118147
119- err = unwind_next_frame_record (state );
148+ err = unwind_next_frame_record (& state -> common );
120149 if (err )
121150 return err ;
122151
123- state -> pc = ptrauth_strip_kernel_insn_pac (state -> pc );
152+ state -> common . pc = ptrauth_strip_kernel_insn_pac (state -> common . pc );
124153
125- return unwind_recover_return_address (state );
154+ return kunwind_recover_return_address (state );
126155}
127156
157+ typedef bool (* kunwind_consume_fn )(const struct kunwind_state * state , void * cookie );
158+
128159static __always_inline void
129- unwind (struct unwind_state * state , stack_trace_consume_fn consume_entry ,
130- void * cookie )
160+ do_kunwind (struct kunwind_state * state , kunwind_consume_fn consume_state ,
161+ void * cookie )
131162{
132- if (unwind_recover_return_address (state ))
163+ if (kunwind_recover_return_address (state ))
133164 return ;
134165
135166 while (1 ) {
136167 int ret ;
137168
138- if (!consume_entry ( cookie , state -> pc ))
169+ if (!consume_state ( state , cookie ))
139170 break ;
140- ret = unwind_next (state );
171+ ret = kunwind_next (state );
141172 if (ret < 0 )
142173 break ;
143174 }
@@ -172,9 +203,10 @@ unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry,
172203 : stackinfo_get_unknown(); \
173204 })
174205
175- noinline noinstr void arch_stack_walk (stack_trace_consume_fn consume_entry ,
176- void * cookie , struct task_struct * task ,
177- struct pt_regs * regs )
206+ static __always_inline void
207+ kunwind_stack_walk (kunwind_consume_fn consume_state ,
208+ void * cookie , struct task_struct * task ,
209+ struct pt_regs * regs )
178210{
179211 struct stack_info stacks [] = {
180212 stackinfo_get_task (task ),
@@ -190,22 +222,48 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
190222 STACKINFO_EFI ,
191223#endif
192224 };
193- struct unwind_state state = {
194- .stacks = stacks ,
195- .nr_stacks = ARRAY_SIZE (stacks ),
225+ struct kunwind_state state = {
226+ .common = {
227+ .stacks = stacks ,
228+ .nr_stacks = ARRAY_SIZE (stacks ),
229+ },
196230 };
197231
198232 if (regs ) {
199233 if (task != current )
200234 return ;
201- unwind_init_from_regs (& state , regs );
235+ kunwind_init_from_regs (& state , regs );
202236 } else if (task == current ) {
203- unwind_init_from_caller (& state );
237+ kunwind_init_from_caller (& state );
204238 } else {
205- unwind_init_from_task (& state , task );
239+ kunwind_init_from_task (& state , task );
206240 }
207241
208- unwind (& state , consume_entry , cookie );
242+ do_kunwind (& state , consume_state , cookie );
243+ }
244+
245+ struct kunwind_consume_entry_data {
246+ stack_trace_consume_fn consume_entry ;
247+ void * cookie ;
248+ };
249+
250+ static bool
251+ arch_kunwind_consume_entry (const struct kunwind_state * state , void * cookie )
252+ {
253+ struct kunwind_consume_entry_data * data = cookie ;
254+ return data -> consume_entry (data -> cookie , state -> common .pc );
255+ }
256+
257+ noinline noinstr void arch_stack_walk (stack_trace_consume_fn consume_entry ,
258+ void * cookie , struct task_struct * task ,
259+ struct pt_regs * regs )
260+ {
261+ struct kunwind_consume_entry_data data = {
262+ .consume_entry = consume_entry ,
263+ .cookie = cookie ,
264+ };
265+
266+ kunwind_stack_walk (arch_kunwind_consume_entry , & data , task , regs );
209267}
210268
211269static bool dump_backtrace_entry (void * arg , unsigned long where )
0 commit comments