[RFC PATCH v2 0/1] arm64: Implement stack trace termination record

Madhavan T. Venkataraman madvenka at linux.microsoft.com
Mon Apr 19 19:16:57 BST 2021


CCing Pavel Tatashin <pasha.tatashin at soleen.com> on request.

Pasha,

This is v2. v1 is here:

https://lore.kernel.org/linux-arm-kernel/20210324184607.120948-1-madvenka@linux.microsoft.com/

Thanks!
                       
Madhavan

On 4/1/21 10:24 PM, madvenka at linux.microsoft.com wrote:
> From: "Madhavan T. Venkataraman" <madvenka at linux.microsoft.com>
> 
> Reliable stacktracing requires that we identify when a stacktrace is
> terminated early. We can do this by ensuring all tasks have a final
> frame record at a known location on their task stack, and checking
> that this is the final frame record in the chain.
> 
> All tasks have a pt_regs structure right after the task stack in the stack
> page. The pt_regs structure contains a stackframe field. Make this stackframe
> field the final frame in the task stack so all stack traces end at a fixed
> stack offset.
> 
> For kernel tasks, this is simple to understand. For user tasks, there is
> some extra detail. User tasks get created via fork() et al. Once they return
> from fork, they enter the kernel only on an EL0 exception. In arm64,
> system calls are also EL0 exceptions.
> 
> The EL0 exception handler uses the task pt_regs mentioned above to save
> register state and call different exception functions. All stack traces
> from EL0 exception code must end at the pt_regs. So, make pt_regs->stackframe
> the final frame in the EL0 exception stack.
> 
> To summarize, task_pt_regs(task)->stackframe will always be the final frame
> in a stack trace.
> 
> Sample stack traces
> ===================
> 
> The final frame for the idle tasks is different from v1. The rest of the
> stack traces are the same.
> 
> Primary CPU's idle task (changed from v1)
> =======================
> 
> [    0.022365]   arch_stack_walk+0x0/0xd0
> [    0.022376]   callfd_stack+0x30/0x60
> [    0.022387]   rest_init+0xd8/0xf8
> [    0.022397]   arch_call_rest_init+0x18/0x24
> [    0.022411]   start_kernel+0x5b8/0x5f4
> [    0.022424]   __primary_switched+0xa8/0xac
> 
> Secondary CPU's idle task (changed from v1)
> =========================
> 
> [    0.022484]   arch_stack_walk+0x0/0xd0
> [    0.022494]   callfd_stack+0x30/0x60
> [    0.022502]   secondary_start_kernel+0x188/0x1e0
> [    0.022513]   __secondary_switched+0x80/0x84
> 
> ---
> Changelog:
> 
> v1
> 	- Set up task_pt_regs(current)->stackframe as the final frame
> 	  when a new task is initialized in copy_thread().
> 
> 	- Create pt_regs for the idle tasks and set up pt_regs->stackframe
> 	  as the final frame for the idle tasks.
> 
> 	- Set up task_pt_regs(current)->stackframe as the final frame in
> 	  the EL0 exception handler so the EL0 exception stack trace ends
> 	  there.
> 
> 	- Terminate the stack trace successfully in unwind_frame() when
> 	  the FP reaches task_pt_regs(current)->stackframe.
> 
> 	- The stack traces (above) in the kernel will terminate at the
> 	  correct place. Debuggers may show an extra record 0x0 at the end
> 	  for pt_regs->stackframe. That said, I did not see that extra frame
> 	  when I did stack traces using gdb.
> v2
> 	- Changed some wordings as suggested by Mark Rutland.
> 
> 	- Removed the synthetic return PC for idle tasks. Changed the
> 	  branches to start_kernel() and secondary_start_kernel() to
> 	  calls so that they will have a proper return PC.
> 
> Madhavan T. Venkataraman (1):
>   arm64: Implement stack trace termination record
> 
>  arch/arm64/kernel/entry.S      |  8 +++++---
>  arch/arm64/kernel/head.S       | 29 +++++++++++++++++++++++------
>  arch/arm64/kernel/process.c    |  5 +++++
>  arch/arm64/kernel/stacktrace.c | 10 +++++-----
>  4 files changed, 38 insertions(+), 14 deletions(-)
> 
> 
> base-commit: 0d02ec6b3136c73c09e7859f0d0e4e2c4c07b49b
> 



More information about the linux-arm-kernel mailing list