Re: [PATCH v13 04/11] arm64: Split unwind_init()

From: Madhavan T. Venkataraman
Date: Tue Feb 15 2022 - 13:04:13 EST




On 2/15/22 07:07, Mark Rutland wrote:
> Hi Madhavan,
>
> The diff itself largely looks good, but we need to actually write the comments.
> Can you pleaes pick up the wording I've written below for those?
>
> That and renaming `unwind_init_from_current` to `unwind_init_from_caller`.
>
> With those I think this is good, but I'd like to see the updated version before
> I provide Acked-by or Reviewed-by tags -- hopefully that's just a formality! :)
>

Will do.

Madhavan

> On Mon, Jan 17, 2022 at 08:56:01AM -0600, madvenka@xxxxxxxxxxxxxxxxxxx wrote:
>> From: "Madhavan T. Venkataraman" <madvenka@xxxxxxxxxxxxxxxxxxx>
>>
>> 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_current() - 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 <madvenka@xxxxxxxxxxxxxxxxxxx>
>> ---
>> arch/arm64/kernel/stacktrace.c | 54 +++++++++++++++++++++++++++-------
>> 1 file changed, 44 insertions(+), 10 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
>> index a1a7ff93b84f..b2b568e5deba 100644
>> --- a/arch/arm64/kernel/stacktrace.c
>> +++ b/arch/arm64/kernel/stacktrace.c
>> @@ -33,11 +33,8 @@
>> */
>>
>>
>> -static void unwind_init(struct unwind_state *state, unsigned long fp,
>> - unsigned long pc)
>> +static void unwind_init_common(struct unwind_state *state)
>> {
>> - state->fp = fp;
>> - state->pc = pc;
>> #ifdef CONFIG_KRETPROBES
>> state->kr_cur = NULL;
>> #endif
>> @@ -56,6 +53,46 @@ static void unwind_init(struct unwind_state *state, unsigned long fp,
>> state->prev_type = STACK_TYPE_UNKNOWN;
>> }
>>
>> +/*
>> + * TODO: document requirements here.
>> + */
>
> Please make this:
>
> /*
> * Start an unwind from a pt_regs.
> *
> * The unwind will begin at the PC within the regs.
> *
> * The regs must be on a stack currently owned by the calling task.
> */
>
>> +static inline void unwind_init_from_regs(struct unwind_state *state,
>> + struct pt_regs *regs)
>> +{
>
> In future we could add:
>
> WARN_ON_ONCE(!on_accessible_stack(current, regs, sizeof(*regs), NULL));
>
> ... to validate the requirements, but I'm happy to lave that for a future patch
> so this patch can be a pure refactoring.
>
>> + unwind_init_common(state);
>> +
>> + state->fp = regs->regs[29];
>> + state->pc = regs->pc;
>> +}
>> +
>> +/*
>> + * TODO: document requirements here.
>> + *
>> + * Note: this is always inlined, and we expect our caller to be a noinline
>> + * function, such that this starts from our caller's caller.
>> + */
>
> Please make this:
>
> /*
> * Start an unwind from a caller.
> *
> * The unwind will begin at the caller of whichever function this is inlined
> * into.
> *
> * The function which invokes this must be noinline.
> */
>
>> +static __always_inline void unwind_init_from_current(struct unwind_state *state)
>
> Can we please rename s/current/caller/ here? That way it's clear *where* in
> current we're unwinding from, and the fact that it's current is implicit but
> obvious.
>
>> +{
>
> Similarly to unwind_init_from_regs(), in a future patch we could add:
>
> WARN_ON_ONCE(task == current);
>
> ... but for now we can omit that so this patch can be a pure refactoring.
>
>> + unwind_init_common(state);
>> +
>> + state->fp = (unsigned long)__builtin_frame_address(1);
>> + state->pc = (unsigned long)__builtin_return_address(0);
>> +}
>> +
>> +/*
>> + * TODO: document requirements here.
>> + *
>> + * The caller guarantees that the task is not running.
>> + */
>
> Please make this:
>
> /*
> * Start an unwind from a blocked task.
> *
> * The unwind will begin at the blocked tasks saved PC (i.e. the caller of
> * cpu_switch_to()).
> *
> * The caller should ensure the task is blocked in cpu_switch_to() for the
> * duration of the unwind, or the unwind will be bogus. It is never valid to
> * call this for the current task.
> */
>
> Thanks,
> Mark.
>
>> +static inline void unwind_init_from_task(struct unwind_state *state,
>> + struct task_struct *task)
>> +{
>> + unwind_init_common(state);
>> +
>> + state->fp = thread_saved_fp(task);
>> + state->pc = thread_saved_pc(task);
>> +}
>> +
>> /*
>> * Unwind from one frame record (A) to the next frame record (B).
>> *
>> @@ -195,14 +232,11 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
>> struct unwind_state state;
>>
>> if (regs)
>> - unwind_init(&state, regs->regs[29], regs->pc);
>> + unwind_init_from_regs(&state, regs);
>> else if (task == current)
>> - unwind_init(&state,
>> - (unsigned long)__builtin_frame_address(1),
>> - (unsigned long)__builtin_return_address(0));
>> + unwind_init_from_current(&state);
>> else
>> - unwind_init(&state, thread_saved_fp(task),
>> - thread_saved_pc(task));
>> + unwind_init_from_task(&state, task);
>>
>> unwind(task, &state, consume_entry, cookie);
>> }
>> --
>> 2.25.1
>>