From: madvenka@linux.microsoft.com To: broonie@kernel.org, mark.rutland@arm.com, jpoimboe@redhat.com, jthierry@redhat.com, catalin.marinas@arm.com, will@kernel.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 1/8] arm64: Implement stack trace termination record Date: Mon, 15 Mar 2021 11:57:53 -0500 [thread overview] Message-ID: <20210315165800.5948-2-madvenka@linux.microsoft.com> (raw) In-Reply-To: <20210315165800.5948-1-madvenka@linux.microsoft.com> From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com> The unwinder needs to be able to reliably tell when it has reached the end of a stack trace. One way to do this is to have the last stack frame at a fixed offset from the base of the task stack. When the unwinder reaches that offset, it knows it is done. Kernel Tasks ============ All tasks except the idle task have a pt_regs structure right after the task stack. This is called the task pt_regs. The pt_regs structure has a special stackframe field. Make this stackframe field the last frame in the task stack. This needs to be done in copy_thread() which initializes a new task's pt_regs and initial CPU context. For the idle task, there is no task pt_regs. For our purpose, we need one. So, create a pt_regs just like other kernel tasks and make pt_regs->stackframe the last frame in the idle task stack. This needs to be done at two places: - On the primary CPU, the boot task runs. It calls start_kernel() and eventually becomes the idle task for the primary CPU. Just before start_kernel() is called, set up the last frame. - On each secondary CPU, a startup task runs that calls secondary_startup_kernel() and eventually becomes the idle task on the secondary CPU. Just before secondary_start_kernel() is called, set up the last frame. User Tasks ========== User tasks are initially set up like kernel tasks when they are created. Then, they return to userland after fork via ret_from_fork(). After that, they enter the kernel only on an EL0 exception. (In arm64, system calls are also EL0 exceptions). The EL0 exception handler stores state in the task pt_regs and calls different functions based on the type of exception. The stack trace for an EL0 exception must end at the task pt_regs. So, make task pt_regs->stackframe as the last frame in the EL0 exception stack. In summary, task pt_regs->stackframe is where a successful stack trace ends. Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com> --- arch/arm64/kernel/entry.S | 8 +++++--- arch/arm64/kernel/head.S | 28 ++++++++++++++++++++++++---- arch/arm64/kernel/process.c | 5 +++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a31a0a713c85..e2dc2e998934 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -261,16 +261,18 @@ alternative_else_nop_endif stp lr, x21, [sp, #S_LR] /* - * For exceptions from EL0, terminate the callchain here. + * For exceptions from EL0, terminate the callchain here at + * task_pt_regs(current)->stackframe. + * * For exceptions from EL1, create a synthetic frame record so the * interrupted code shows up in the backtrace. */ .if \el == 0 - mov x29, xzr + stp xzr, xzr, [sp, #S_STACKFRAME] .else stp x29, x22, [sp, #S_STACKFRAME] - add x29, sp, #S_STACKFRAME .endif + add x29, sp, #S_STACKFRAME #ifdef CONFIG_ARM64_SW_TTBR0_PAN alternative_if_not ARM64_HAS_PAN diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 66b0e0b66e31..2769b20934d4 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -393,6 +393,28 @@ SYM_FUNC_START_LOCAL(__create_page_tables) ret x28 SYM_FUNC_END(__create_page_tables) + /* + * The boot task becomes the idle task for the primary CPU. The + * CPU startup task on each secondary CPU becomes the idle task + * for the secondary CPU. + * + * The idle task does not require pt_regs. But create a dummy + * pt_regs so that task_pt_regs(idle_task)->stackframe can be + * set up to be the last frame on the idle task stack just like + * all the other kernel tasks. This helps the unwinder to + * terminate the stack trace at a well-known stack offset. + * + * Also, set up the last return PC to be ret_from_fork() just + * like all the other kernel tasks so that the stack trace of + * all kernel tasks ends with the same function. + */ + .macro setup_last_frame + sub sp, sp, #PT_REGS_SIZE + stp xzr, xzr, [sp, #S_STACKFRAME] + add x29, sp, #S_STACKFRAME + ldr x30, =ret_from_fork + .endm + /* * The following fragment of code is executed with the MMU enabled. * @@ -447,8 +469,7 @@ SYM_FUNC_START_LOCAL(__primary_switched) #endif bl switch_to_vhe // Prefer VHE if possible add sp, sp, #16 - mov x29, #0 - mov x30, #0 + setup_last_frame b start_kernel SYM_FUNC_END(__primary_switched) @@ -606,8 +627,7 @@ SYM_FUNC_START_LOCAL(__secondary_switched) cbz x2, __secondary_too_slow msr sp_el0, x2 scs_load x2, x3 - mov x29, #0 - mov x30, #0 + setup_last_frame #ifdef CONFIG_ARM64_PTR_AUTH ptrauth_keys_init_cpu x2, x3, x4, x5 diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 325c83b1a24d..7ffa689e8b60 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -437,6 +437,11 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, } p->thread.cpu_context.pc = (unsigned long)ret_from_fork; p->thread.cpu_context.sp = (unsigned long)childregs; + /* + * For the benefit of the unwinder, set up childregs->stackframe + * as the last frame for the new task. + */ + p->thread.cpu_context.fp = (unsigned long)childregs->stackframe; ptrace_hw_copy_thread(p); -- 2.25.1
WARNING: multiple messages have this Message-ID (diff)
From: madvenka@linux.microsoft.com To: broonie@kernel.org, mark.rutland@arm.com, jpoimboe@redhat.com, jthierry@redhat.com, catalin.marinas@arm.com, will@kernel.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 1/8] arm64: Implement stack trace termination record Date: Mon, 15 Mar 2021 11:57:53 -0500 [thread overview] Message-ID: <20210315165800.5948-2-madvenka@linux.microsoft.com> (raw) In-Reply-To: <20210315165800.5948-1-madvenka@linux.microsoft.com> From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com> The unwinder needs to be able to reliably tell when it has reached the end of a stack trace. One way to do this is to have the last stack frame at a fixed offset from the base of the task stack. When the unwinder reaches that offset, it knows it is done. Kernel Tasks ============ All tasks except the idle task have a pt_regs structure right after the task stack. This is called the task pt_regs. The pt_regs structure has a special stackframe field. Make this stackframe field the last frame in the task stack. This needs to be done in copy_thread() which initializes a new task's pt_regs and initial CPU context. For the idle task, there is no task pt_regs. For our purpose, we need one. So, create a pt_regs just like other kernel tasks and make pt_regs->stackframe the last frame in the idle task stack. This needs to be done at two places: - On the primary CPU, the boot task runs. It calls start_kernel() and eventually becomes the idle task for the primary CPU. Just before start_kernel() is called, set up the last frame. - On each secondary CPU, a startup task runs that calls secondary_startup_kernel() and eventually becomes the idle task on the secondary CPU. Just before secondary_start_kernel() is called, set up the last frame. User Tasks ========== User tasks are initially set up like kernel tasks when they are created. Then, they return to userland after fork via ret_from_fork(). After that, they enter the kernel only on an EL0 exception. (In arm64, system calls are also EL0 exceptions). The EL0 exception handler stores state in the task pt_regs and calls different functions based on the type of exception. The stack trace for an EL0 exception must end at the task pt_regs. So, make task pt_regs->stackframe as the last frame in the EL0 exception stack. In summary, task pt_regs->stackframe is where a successful stack trace ends. Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com> --- arch/arm64/kernel/entry.S | 8 +++++--- arch/arm64/kernel/head.S | 28 ++++++++++++++++++++++++---- arch/arm64/kernel/process.c | 5 +++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a31a0a713c85..e2dc2e998934 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -261,16 +261,18 @@ alternative_else_nop_endif stp lr, x21, [sp, #S_LR] /* - * For exceptions from EL0, terminate the callchain here. + * For exceptions from EL0, terminate the callchain here at + * task_pt_regs(current)->stackframe. + * * For exceptions from EL1, create a synthetic frame record so the * interrupted code shows up in the backtrace. */ .if \el == 0 - mov x29, xzr + stp xzr, xzr, [sp, #S_STACKFRAME] .else stp x29, x22, [sp, #S_STACKFRAME] - add x29, sp, #S_STACKFRAME .endif + add x29, sp, #S_STACKFRAME #ifdef CONFIG_ARM64_SW_TTBR0_PAN alternative_if_not ARM64_HAS_PAN diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 66b0e0b66e31..2769b20934d4 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -393,6 +393,28 @@ SYM_FUNC_START_LOCAL(__create_page_tables) ret x28 SYM_FUNC_END(__create_page_tables) + /* + * The boot task becomes the idle task for the primary CPU. The + * CPU startup task on each secondary CPU becomes the idle task + * for the secondary CPU. + * + * The idle task does not require pt_regs. But create a dummy + * pt_regs so that task_pt_regs(idle_task)->stackframe can be + * set up to be the last frame on the idle task stack just like + * all the other kernel tasks. This helps the unwinder to + * terminate the stack trace at a well-known stack offset. + * + * Also, set up the last return PC to be ret_from_fork() just + * like all the other kernel tasks so that the stack trace of + * all kernel tasks ends with the same function. + */ + .macro setup_last_frame + sub sp, sp, #PT_REGS_SIZE + stp xzr, xzr, [sp, #S_STACKFRAME] + add x29, sp, #S_STACKFRAME + ldr x30, =ret_from_fork + .endm + /* * The following fragment of code is executed with the MMU enabled. * @@ -447,8 +469,7 @@ SYM_FUNC_START_LOCAL(__primary_switched) #endif bl switch_to_vhe // Prefer VHE if possible add sp, sp, #16 - mov x29, #0 - mov x30, #0 + setup_last_frame b start_kernel SYM_FUNC_END(__primary_switched) @@ -606,8 +627,7 @@ SYM_FUNC_START_LOCAL(__secondary_switched) cbz x2, __secondary_too_slow msr sp_el0, x2 scs_load x2, x3 - mov x29, #0 - mov x30, #0 + setup_last_frame #ifdef CONFIG_ARM64_PTR_AUTH ptrauth_keys_init_cpu x2, x3, x4, x5 diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 325c83b1a24d..7ffa689e8b60 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -437,6 +437,11 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, } p->thread.cpu_context.pc = (unsigned long)ret_from_fork; p->thread.cpu_context.sp = (unsigned long)childregs; + /* + * For the benefit of the unwinder, set up childregs->stackframe + * as the last frame for the new task. + */ + p->thread.cpu_context.fp = (unsigned long)childregs->stackframe; ptrace_hw_copy_thread(p); -- 2.25.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2021-03-15 16:59 UTC|newest] Thread overview: 110+ messages / expand[flat|nested] mbox.gz Atom feed top [not found] <5997dfe8d261a3a543667b83c902883c1e4bd270> 2021-03-15 16:57 ` [RFC PATCH v2 0/8] arm64: Implement reliable stack trace madvenka 2021-03-15 16:57 ` madvenka 2021-03-15 16:57 ` madvenka [this message] 2021-03-15 16:57 ` [RFC PATCH v2 1/8] arm64: Implement stack trace termination record madvenka 2021-03-18 15:09 ` Mark Brown 2021-03-18 15:09 ` Mark Brown 2021-03-18 20:26 ` Madhavan T. Venkataraman 2021-03-18 20:26 ` Madhavan T. Venkataraman 2021-03-19 12:30 ` Mark Brown 2021-03-19 12:30 ` Mark Brown 2021-03-19 14:29 ` Madhavan T. Venkataraman 2021-03-19 14:29 ` Madhavan T. Venkataraman 2021-03-19 18:19 ` Madhavan T. Venkataraman 2021-03-19 18:19 ` Madhavan T. Venkataraman 2021-03-19 22:03 ` Madhavan T. Venkataraman 2021-03-19 22:03 ` Madhavan T. Venkataraman 2021-03-23 10:24 ` Mark Rutland 2021-03-23 10:24 ` Mark Rutland 2021-03-23 12:39 ` Madhavan T. Venkataraman 2021-03-23 12:39 ` Madhavan T. Venkataraman 2021-03-15 16:57 ` [RFC PATCH v2 2/8] arm64: Implement frame types madvenka 2021-03-15 16:57 ` madvenka 2021-03-18 17:40 ` Mark Brown 2021-03-18 17:40 ` Mark Brown 2021-03-18 22:22 ` Madhavan T. Venkataraman 2021-03-18 22:22 ` Madhavan T. Venkataraman 2021-03-19 13:22 ` Mark Brown 2021-03-19 13:22 ` Mark Brown 2021-03-19 14:40 ` Madhavan T. Venkataraman 2021-03-19 14:40 ` Madhavan T. Venkataraman 2021-03-19 15:02 ` Madhavan T. Venkataraman 2021-03-19 15:02 ` Madhavan T. Venkataraman 2021-03-19 16:20 ` Mark Brown 2021-03-19 16:20 ` Mark Brown 2021-03-19 16:27 ` Madhavan T. Venkataraman 2021-03-19 16:27 ` Madhavan T. Venkataraman 2021-03-23 10:34 ` Mark Rutland 2021-03-23 10:34 ` Mark Rutland 2021-03-15 16:57 ` [RFC PATCH v2 3/8] arm64: Terminate the stack trace at TASK_FRAME and EL0_FRAME madvenka 2021-03-15 16:57 ` madvenka 2021-03-18 18:26 ` Mark Brown 2021-03-18 18:26 ` Mark Brown 2021-03-18 20:29 ` Madhavan T. Venkataraman 2021-03-18 20:29 ` Madhavan T. Venkataraman 2021-03-23 10:36 ` Mark Rutland 2021-03-23 10:36 ` Mark Rutland 2021-03-23 12:40 ` Madhavan T. Venkataraman 2021-03-23 12:40 ` Madhavan T. Venkataraman 2021-03-15 16:57 ` [RFC PATCH v2 4/8] arm64: Detect an EL1 exception frame and mark a stack trace unreliable madvenka 2021-03-15 16:57 ` madvenka 2021-03-23 10:42 ` Mark Rutland 2021-03-23 10:42 ` Mark Rutland 2021-03-23 12:46 ` Madhavan T. Venkataraman 2021-03-23 12:46 ` Madhavan T. Venkataraman 2021-03-23 13:04 ` Mark Rutland 2021-03-23 13:04 ` Mark Rutland 2021-03-23 13:31 ` Madhavan T. Venkataraman 2021-03-23 13:31 ` Madhavan T. Venkataraman 2021-03-23 14:33 ` Mark Rutland 2021-03-23 14:33 ` Mark Rutland 2021-03-23 15:22 ` Madhavan T. Venkataraman 2021-03-23 15:22 ` Madhavan T. Venkataraman 2021-03-15 16:57 ` [RFC PATCH v2 5/8] arm64: Detect an FTRACE " madvenka 2021-03-15 16:57 ` madvenka 2021-03-23 10:51 ` Mark Rutland 2021-03-23 10:51 ` Mark Rutland 2021-03-23 12:56 ` Madhavan T. Venkataraman 2021-03-23 12:56 ` Madhavan T. Venkataraman 2021-03-23 13:36 ` Mark Rutland 2021-03-23 13:36 ` Mark Rutland 2021-03-23 13:38 ` Madhavan T. Venkataraman 2021-03-23 13:38 ` Madhavan T. Venkataraman 2021-03-23 14:15 ` Madhavan T. Venkataraman 2021-03-23 14:15 ` Madhavan T. Venkataraman 2021-03-23 14:57 ` Mark Rutland 2021-03-23 14:57 ` Mark Rutland 2021-03-23 15:26 ` Madhavan T. Venkataraman 2021-03-23 15:26 ` Madhavan T. Venkataraman 2021-03-23 16:20 ` Madhavan T. Venkataraman 2021-03-23 16:20 ` Madhavan T. Venkataraman 2021-03-23 17:02 ` Mark Rutland 2021-03-23 17:02 ` Mark Rutland 2021-03-23 17:23 ` Madhavan T. Venkataraman 2021-03-23 17:23 ` Madhavan T. Venkataraman 2021-03-23 17:27 ` Madhavan T. Venkataraman 2021-03-23 17:27 ` Madhavan T. Venkataraman 2021-03-23 18:27 ` Mark Brown 2021-03-23 18:27 ` Mark Brown 2021-03-23 20:23 ` Madhavan T. Venkataraman 2021-03-23 20:23 ` Madhavan T. Venkataraman 2021-03-23 18:30 ` Mark Rutland 2021-03-23 18:30 ` Mark Rutland 2021-03-23 20:24 ` Madhavan T. Venkataraman 2021-03-23 20:24 ` Madhavan T. Venkataraman 2021-03-23 21:04 ` Madhavan T. Venkataraman 2021-03-23 21:04 ` Madhavan T. Venkataraman 2021-03-23 16:48 ` Mark Rutland 2021-03-23 16:48 ` Mark Rutland 2021-03-23 16:53 ` Madhavan T. Venkataraman 2021-03-23 16:53 ` Madhavan T. Venkataraman 2021-03-23 17:09 ` Mark Rutland 2021-03-23 17:09 ` Mark Rutland 2021-03-15 16:57 ` [RFC PATCH v2 6/8] arm64: Check the return PC of every stack frame madvenka 2021-03-15 16:57 ` madvenka 2021-03-15 16:57 ` [RFC PATCH v2 7/8] arm64: Detect kretprobed functions in stack trace madvenka 2021-03-15 16:57 ` madvenka 2021-03-15 16:58 ` [RFC PATCH v2 8/8] arm64: Implement arch_stack_walk_reliable() madvenka 2021-03-15 16:58 ` madvenka 2021-03-15 19:01 ` [RFC PATCH v2 0/8] arm64: Implement reliable stack trace Madhavan T. Venkataraman 2021-03-15 19:01 ` Madhavan T. Venkataraman
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210315165800.5948-2-madvenka@linux.microsoft.com \ --to=madvenka@linux.microsoft.com \ --cc=broonie@kernel.org \ --cc=catalin.marinas@arm.com \ --cc=jpoimboe@redhat.com \ --cc=jthierry@redhat.com \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=live-patching@vger.kernel.org \ --cc=mark.rutland@arm.com \ --cc=will@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.