Skip to content

Commit a019d8a

Browse files
madvenka786willdeacon
authored andcommitted
arm64: Split unwind_init()
unwind_init() is currently a single function that initializes all of the unwind state. Split it into the following functions and call them appropriately: - unwind_init_from_regs() - initialize from regs passed by caller. - unwind_init_from_caller() - initialize for the current task from the caller of arch_stack_walk(). - unwind_init_from_task() - initialize from the saved state of a task other than the current task. In this case, the other task must not be running. This is done for two reasons: - the different ways of initializing are clear - specialized code can be added to each initializer in the future. Signed-off-by: Madhavan T. Venkataraman <[email protected]> Reviewed-by: Mark Brown <[email protected]> Acked-by: Mark Rutland <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 446297b commit a019d8a

File tree

1 file changed

+55
-11
lines changed

1 file changed

+55
-11
lines changed

arch/arm64/kernel/stacktrace.c

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,8 @@ struct unwind_state {
5050
#endif
5151
};
5252

53-
static notrace void unwind_init(struct unwind_state *state, unsigned long fp,
54-
unsigned long pc)
53+
static void unwind_init_common(struct unwind_state *state)
5554
{
56-
state->fp = fp;
57-
state->pc = pc;
5855
#ifdef CONFIG_KRETPROBES
5956
state->kr_cur = NULL;
6057
#endif
@@ -72,7 +69,57 @@ static notrace void unwind_init(struct unwind_state *state, unsigned long fp,
7269
state->prev_fp = 0;
7370
state->prev_type = STACK_TYPE_UNKNOWN;
7471
}
75-
NOKPROBE_SYMBOL(unwind_init);
72+
73+
/*
74+
* Start an unwind from a pt_regs.
75+
*
76+
* The unwind will begin at the PC within the regs.
77+
*
78+
* The regs must be on a stack currently owned by the calling task.
79+
*/
80+
static inline void unwind_init_from_regs(struct unwind_state *state,
81+
struct pt_regs *regs)
82+
{
83+
unwind_init_common(state);
84+
85+
state->fp = regs->regs[29];
86+
state->pc = regs->pc;
87+
}
88+
89+
/*
90+
* Start an unwind from a caller.
91+
*
92+
* The unwind will begin at the caller of whichever function this is inlined
93+
* into.
94+
*
95+
* The function which invokes this must be noinline.
96+
*/
97+
static __always_inline void unwind_init_from_caller(struct unwind_state *state)
98+
{
99+
unwind_init_common(state);
100+
101+
state->fp = (unsigned long)__builtin_frame_address(1);
102+
state->pc = (unsigned long)__builtin_return_address(0);
103+
}
104+
105+
/*
106+
* Start an unwind from a blocked task.
107+
*
108+
* The unwind will begin at the blocked tasks saved PC (i.e. the caller of
109+
* cpu_switch_to()).
110+
*
111+
* The caller should ensure the task is blocked in cpu_switch_to() for the
112+
* duration of the unwind, or the unwind will be bogus. It is never valid to
113+
* call this for the current task.
114+
*/
115+
static inline void unwind_init_from_task(struct unwind_state *state,
116+
struct task_struct *task)
117+
{
118+
unwind_init_common(state);
119+
120+
state->fp = thread_saved_fp(task);
121+
state->pc = thread_saved_pc(task);
122+
}
76123

77124
/*
78125
* Unwind from one frame record (A) to the next frame record (B).
@@ -213,14 +260,11 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
213260
struct unwind_state state;
214261

215262
if (regs)
216-
unwind_init(&state, regs->regs[29], regs->pc);
263+
unwind_init_from_regs(&state, regs);
217264
else if (task == current)
218-
unwind_init(&state,
219-
(unsigned long)__builtin_frame_address(1),
220-
(unsigned long)__builtin_return_address(0));
265+
unwind_init_from_caller(&state);
221266
else
222-
unwind_init(&state, thread_saved_fp(task),
223-
thread_saved_pc(task));
267+
unwind_init_from_task(&state, task);
224268

225269
unwind(task, &state, consume_entry, cookie);
226270
}

0 commit comments

Comments
 (0)