25
25
*
26
26
* The regs must be on a stack currently owned by the calling task.
27
27
*/
28
- static __always_inline void unwind_init_from_regs (struct unwind_state * state ,
29
- struct pt_regs * regs )
28
+ static __always_inline void
29
+ unwind_init_from_regs (struct unwind_state * state ,
30
+ struct pt_regs * regs )
30
31
{
31
32
unwind_init_common (state , current );
32
33
@@ -42,7 +43,8 @@ static __always_inline void unwind_init_from_regs(struct unwind_state *state,
42
43
*
43
44
* The function which invokes this must be noinline.
44
45
*/
45
- static __always_inline void unwind_init_from_caller (struct unwind_state * state )
46
+ static __always_inline void
47
+ unwind_init_from_caller (struct unwind_state * state )
46
48
{
47
49
unwind_init_common (state , current );
48
50
@@ -60,23 +62,51 @@ static __always_inline void unwind_init_from_caller(struct unwind_state *state)
60
62
* duration of the unwind, or the unwind will be bogus. It is never valid to
61
63
* call this for the current task.
62
64
*/
63
- static __always_inline void unwind_init_from_task (struct unwind_state * state ,
64
- struct task_struct * task )
65
+ static __always_inline void
66
+ unwind_init_from_task (struct unwind_state * state ,
67
+ struct task_struct * task )
65
68
{
66
69
unwind_init_common (state , task );
67
70
68
71
state -> fp = thread_saved_fp (task );
69
72
state -> pc = thread_saved_pc (task );
70
73
}
71
74
75
+ static __always_inline int
76
+ unwind_recover_return_address (struct unwind_state * state )
77
+ {
78
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
79
+ if (state -> task -> ret_stack &&
80
+ (state -> pc == (unsigned long )return_to_handler )) {
81
+ 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 ))
85
+ return - EINVAL ;
86
+ state -> pc = orig_pc ;
87
+ }
88
+ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
89
+
90
+ #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 );
95
+ }
96
+ #endif /* CONFIG_KRETPROBES */
97
+
98
+ return 0 ;
99
+ }
100
+
72
101
/*
73
102
* Unwind from one frame record (A) to the next frame record (B).
74
103
*
75
104
* We terminate early if the location of B indicates a malformed chain of frame
76
105
* records (e.g. a cycle), determined based on the location and fp value of A
77
106
* and the location (but not the fp value) of B.
78
107
*/
79
- static int notrace unwind_next (struct unwind_state * state )
108
+ static __always_inline int
109
+ unwind_next (struct unwind_state * state )
80
110
{
81
111
struct task_struct * tsk = state -> task ;
82
112
unsigned long fp = state -> fp ;
@@ -90,37 +120,18 @@ static int notrace unwind_next(struct unwind_state *state)
90
120
if (err )
91
121
return err ;
92
122
93
- state -> pc = ptrauth_strip_insn_pac (state -> pc );
94
-
95
- #ifdef CONFIG_FUNCTION_GRAPH_TRACER
96
- if (tsk -> ret_stack &&
97
- (state -> pc == (unsigned long )return_to_handler )) {
98
- unsigned long orig_pc ;
99
- /*
100
- * This is a case where function graph tracer has
101
- * modified a return address (LR) in a stack frame
102
- * to hook a function return.
103
- * So replace it to an original value.
104
- */
105
- orig_pc = ftrace_graph_ret_addr (tsk , NULL , state -> pc ,
106
- (void * )state -> fp );
107
- if (WARN_ON_ONCE (state -> pc == orig_pc ))
108
- return - EINVAL ;
109
- state -> pc = orig_pc ;
110
- }
111
- #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
112
- #ifdef CONFIG_KRETPROBES
113
- if (is_kretprobe_trampoline (state -> pc ))
114
- state -> pc = kretprobe_find_ret_addr (tsk , (void * )state -> fp , & state -> kr_cur );
115
- #endif
123
+ state -> pc = ptrauth_strip_kernel_insn_pac (state -> pc );
116
124
117
- return 0 ;
125
+ return unwind_recover_return_address ( state ) ;
118
126
}
119
- NOKPROBE_SYMBOL (unwind_next );
120
127
121
- static void notrace unwind (struct unwind_state * state ,
122
- stack_trace_consume_fn consume_entry , void * cookie )
128
+ static __always_inline void
129
+ unwind (struct unwind_state * state , stack_trace_consume_fn consume_entry ,
130
+ void * cookie )
123
131
{
132
+ if (unwind_recover_return_address (state ))
133
+ return ;
134
+
124
135
while (1 ) {
125
136
int ret ;
126
137
@@ -131,40 +142,6 @@ static void notrace unwind(struct unwind_state *state,
131
142
break ;
132
143
}
133
144
}
134
- NOKPROBE_SYMBOL (unwind );
135
-
136
- static bool dump_backtrace_entry (void * arg , unsigned long where )
137
- {
138
- char * loglvl = arg ;
139
- printk ("%s %pSb\n" , loglvl , (void * )where );
140
- return true;
141
- }
142
-
143
- void dump_backtrace (struct pt_regs * regs , struct task_struct * tsk ,
144
- const char * loglvl )
145
- {
146
- pr_debug ("%s(regs = %p tsk = %p)\n" , __func__ , regs , tsk );
147
-
148
- if (regs && user_mode (regs ))
149
- return ;
150
-
151
- if (!tsk )
152
- tsk = current ;
153
-
154
- if (!try_get_task_stack (tsk ))
155
- return ;
156
-
157
- printk ("%sCall trace:\n" , loglvl );
158
- arch_stack_walk (dump_backtrace_entry , (void * )loglvl , tsk , regs );
159
-
160
- put_task_stack (tsk );
161
- }
162
-
163
- void show_stack (struct task_struct * tsk , unsigned long * sp , const char * loglvl )
164
- {
165
- dump_backtrace (NULL , tsk , loglvl );
166
- barrier ();
167
- }
168
145
169
146
/*
170
147
* Per-cpu stacks are only accessible when unwinding the current task in a
@@ -230,3 +207,36 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
230
207
231
208
unwind (& state , consume_entry , cookie );
232
209
}
210
+
211
+ static bool dump_backtrace_entry (void * arg , unsigned long where )
212
+ {
213
+ char * loglvl = arg ;
214
+ printk ("%s %pSb\n" , loglvl , (void * )where );
215
+ return true;
216
+ }
217
+
218
+ void dump_backtrace (struct pt_regs * regs , struct task_struct * tsk ,
219
+ const char * loglvl )
220
+ {
221
+ pr_debug ("%s(regs = %p tsk = %p)\n" , __func__ , regs , tsk );
222
+
223
+ if (regs && user_mode (regs ))
224
+ return ;
225
+
226
+ if (!tsk )
227
+ tsk = current ;
228
+
229
+ if (!try_get_task_stack (tsk ))
230
+ return ;
231
+
232
+ printk ("%sCall trace:\n" , loglvl );
233
+ arch_stack_walk (dump_backtrace_entry , (void * )loglvl , tsk , regs );
234
+
235
+ put_task_stack (tsk );
236
+ }
237
+
238
+ void show_stack (struct task_struct * tsk , unsigned long * sp , const char * loglvl )
239
+ {
240
+ dump_backtrace (NULL , tsk , loglvl );
241
+ barrier ();
242
+ }
0 commit comments