Skip to content

Commit 41cff14

Browse files
committed
Merge branch 'for-next/stacktrace' into for-next/core
* for-next/stacktrace: arm64: stacktrace: factor out kunwind_stack_walk() arm64: stacktrace: factor out kernel unwind state
2 parents ef4896b + 1aba06e commit 41cff14

File tree

3 files changed

+104
-63
lines changed

3 files changed

+104
-63
lines changed

arch/arm64/include/asm/stacktrace/common.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#ifndef __ASM_STACKTRACE_COMMON_H
1010
#define __ASM_STACKTRACE_COMMON_H
1111

12-
#include <linux/kprobes.h>
1312
#include <linux/types.h>
1413

1514
struct stack_info {
@@ -23,23 +22,13 @@ struct stack_info {
2322
* @fp: The fp value in the frame record (or the real fp)
2423
* @pc: The lr value in the frame record (or the real lr)
2524
*
26-
* @kr_cur: When KRETPROBES is selected, holds the kretprobe instance
27-
* associated with the most recently encountered replacement lr
28-
* value.
29-
*
30-
* @task: The task being unwound.
31-
*
3225
* @stack: The stack currently being unwound.
3326
* @stacks: An array of stacks which can be unwound.
3427
* @nr_stacks: The number of stacks in @stacks.
3528
*/
3629
struct unwind_state {
3730
unsigned long fp;
3831
unsigned long pc;
39-
#ifdef CONFIG_KRETPROBES
40-
struct llist_node *kr_cur;
41-
#endif
42-
struct task_struct *task;
4332

4433
struct stack_info stack;
4534
struct stack_info *stacks;
@@ -66,14 +55,8 @@ static inline bool stackinfo_on_stack(const struct stack_info *info,
6655
return true;
6756
}
6857

69-
static inline void unwind_init_common(struct unwind_state *state,
70-
struct task_struct *task)
58+
static inline void unwind_init_common(struct unwind_state *state)
7159
{
72-
state->task = task;
73-
#ifdef CONFIG_KRETPROBES
74-
state->kr_cur = NULL;
75-
#endif
76-
7760
state->stack = stackinfo_get_unknown();
7861
}
7962

arch/arm64/include/asm/stacktrace/nvhe.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state,
3131
unsigned long fp,
3232
unsigned long pc)
3333
{
34-
unwind_init_common(state, NULL);
34+
unwind_init_common(state);
3535

3636
state->fp = fp;
3737
state->pc = pc;

arch/arm64/kernel/stacktrace.c

Lines changed: 102 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
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>
@@ -18,6 +19,31 @@
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
*
@@ -26,13 +52,13 @@
2652
* The regs must be on a stack currently owned by the calling task.
2753
*/
2854
static __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
*/
4672
static __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
*/
6591
static __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

75101
static __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
*/
108137
static __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+
128159
static __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

211269
static bool dump_backtrace_entry(void *arg, unsigned long where)

0 commit comments

Comments
 (0)