Skip to content

Commit 1beef60

Browse files
Mark Rutlandwilldeacon
Mark Rutland
authored andcommitted
arm64: stacktrace: factor out kernel unwind state
On arm64 we share some unwinding code between the regular kernel unwinder and the KVM hyp unwinder. Some of this common code only matters to the regular unwinder, e.g. the `kr_cur` and `task` fields in the common struct unwind_state. We're likely to add more state which only matters for regular kernel unwinding (or only for hyp unwinding). In preparation for such changes, this patch factors out the kernel-specific state into a new struct kunwind_state, and updates the kernel unwind code accordingly. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Kalesh Singh <[email protected]> Cc: Madhavan T. Venkataraman <[email protected]> Cc: Mark Brown <[email protected]> Cc: Puranjay Mohan <[email protected]> Cc: Will Deacon <[email protected]> Reviewed-by: Puranjay Mohan <[email protected]> Reviewed-by: Kalesh Singh <[email protected]> Reviewed-by: Madhavan T. Venkataraman <[email protected]> Reviewed-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 2cc14f5 commit 1beef60

File tree

3 files changed

+74
-60
lines changed

3 files changed

+74
-60
lines changed

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

+1-18
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

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

+72-41
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,38 @@ 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

128157
static __always_inline void
129-
unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry,
130-
void *cookie)
158+
do_kunwind(struct kunwind_state *state, stack_trace_consume_fn consume_entry,
159+
void *cookie)
131160
{
132-
if (unwind_recover_return_address(state))
161+
if (kunwind_recover_return_address(state))
133162
return;
134163

135164
while (1) {
136165
int ret;
137166

138-
if (!consume_entry(cookie, state->pc))
167+
if (!consume_entry(cookie, state->common.pc))
139168
break;
140-
ret = unwind_next(state);
169+
ret = kunwind_next(state);
141170
if (ret < 0)
142171
break;
143172
}
@@ -190,22 +219,24 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
190219
STACKINFO_EFI,
191220
#endif
192221
};
193-
struct unwind_state state = {
194-
.stacks = stacks,
195-
.nr_stacks = ARRAY_SIZE(stacks),
222+
struct kunwind_state state = {
223+
.common = {
224+
.stacks = stacks,
225+
.nr_stacks = ARRAY_SIZE(stacks),
226+
},
196227
};
197228

198229
if (regs) {
199230
if (task != current)
200231
return;
201-
unwind_init_from_regs(&state, regs);
232+
kunwind_init_from_regs(&state, regs);
202233
} else if (task == current) {
203-
unwind_init_from_caller(&state);
234+
kunwind_init_from_caller(&state);
204235
} else {
205-
unwind_init_from_task(&state, task);
236+
kunwind_init_from_task(&state, task);
206237
}
207238

208-
unwind(&state, consume_entry, cookie);
239+
do_kunwind(&state, consume_entry, cookie);
209240
}
210241

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

0 commit comments

Comments
 (0)