diff mbox series

[v3,09/10] ARM: call_with_stack: add unwind support

Message ID 20211017131723.4034662-10-ardb@kernel.org (mailing list archive)
State New, archived
Headers show
Series ARM: add support for IRQ stacks | expand

Commit Message

Ard Biesheuvel Oct. 17, 2021, 1:17 p.m. UTC
Restructure the code and add the unwind annotations so that both the
frame pointer unwinder as well as the EHABI unwind info based unwinder
will be able to follow the call stack through call_with_stack().

Since GCC and Clang use different formats for the stack frame, two
methods are implemented: a GCC version that pushes fp, sp, lr and pc for
compatibility with the frame pointer unwinder, and a second version that
works with Clang, as well as with the EHABI unwinder both in ARM and
Thumb2 modes.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Tested-by: Keith Packard <keithpac@amazon.com>
---
 arch/arm/lib/call_with_stack.S | 33 +++++++++++++++-----
 1 file changed, 25 insertions(+), 8 deletions(-)

Comments

Nick Desaulniers Oct. 18, 2021, 8:50 p.m. UTC | #1
On Sun, Oct 17, 2021 at 6:17 AM Ard Biesheuvel <ardb@kernel.org> wrote:
>
> Restructure the code and add the unwind annotations so that both the
> frame pointer unwinder as well as the EHABI unwind info based unwinder
> will be able to follow the call stack through call_with_stack().
>
> Since GCC and Clang use different formats for the stack frame, two
> methods are implemented: a GCC version that pushes fp, sp, lr and pc for
> compatibility with the frame pointer unwinder, and a second version that
> works with Clang, as well as with the EHABI unwinder both in ARM and
> Thumb2 modes.

Thanks for the patch!
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>

>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> Tested-by: Keith Packard <keithpac@amazon.com>
> ---
>  arch/arm/lib/call_with_stack.S | 33 +++++++++++++++-----
>  1 file changed, 25 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm/lib/call_with_stack.S b/arch/arm/lib/call_with_stack.S
> index 28b0341ae786..0a268a6c513c 100644
> --- a/arch/arm/lib/call_with_stack.S
> +++ b/arch/arm/lib/call_with_stack.S
> @@ -8,25 +8,42 @@
>
>  #include <linux/linkage.h>
>  #include <asm/assembler.h>
> +#include <asm/unwind.h>
>
>  /*
>   * void call_with_stack(void (*fn)(void *), void *arg, void *sp)
>   *
>   * Change the stack to that pointed at by sp, then invoke fn(arg) with
>   * the new stack.
> + *
> + * The sequence below follows the APCS frame convention for frame pointer
> + * unwinding, and implements the unwinder annotations needed by the EABI
> + * unwinder.
>   */
> -ENTRY(call_with_stack)
> -       str     sp, [r2, #-4]!
> -       str     lr, [r2, #-4]!
>
> +ENTRY(call_with_stack)
> +#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
> +       mov     ip, sp
> +       push    {fp, ip, lr, pc}
> +       sub     fp, ip, #4
> +#else
> +UNWIND( .fnstart               )
> +UNWIND( .save  {fpreg, lr}     )
> +       push    {fpreg, lr}
> +UNWIND( .setfp fpreg, sp       )
> +       mov     fpreg, sp
> +#endif
>         mov     sp, r2
>         mov     r2, r0
>         mov     r0, r1
>
> -       badr    lr, 1f
> -       ret     r2
> +       bl_r    r2
>
> -1:     ldr     lr, [sp]
> -       ldr     sp, [sp, #4]
> -       ret     lr
> +#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
> +       ldmdb   fp, {fp, sp, pc}
> +#else
> +       mov     sp, fpreg
> +       pop     {fpreg, pc}
> +UNWIND( .fnend                 )
> +#endif
>  ENDPROC(call_with_stack)
> --
> 2.30.2
>
diff mbox series

Patch

diff --git a/arch/arm/lib/call_with_stack.S b/arch/arm/lib/call_with_stack.S
index 28b0341ae786..0a268a6c513c 100644
--- a/arch/arm/lib/call_with_stack.S
+++ b/arch/arm/lib/call_with_stack.S
@@ -8,25 +8,42 @@ 
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 /*
  * void call_with_stack(void (*fn)(void *), void *arg, void *sp)
  *
  * Change the stack to that pointed at by sp, then invoke fn(arg) with
  * the new stack.
+ *
+ * The sequence below follows the APCS frame convention for frame pointer
+ * unwinding, and implements the unwinder annotations needed by the EABI
+ * unwinder.
  */
-ENTRY(call_with_stack)
-	str	sp, [r2, #-4]!
-	str	lr, [r2, #-4]!
 
+ENTRY(call_with_stack)
+#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
+	mov	ip, sp
+	push	{fp, ip, lr, pc}
+	sub	fp, ip, #4
+#else
+UNWIND( .fnstart		)
+UNWIND( .save	{fpreg, lr}	)
+	push	{fpreg, lr}
+UNWIND( .setfp	fpreg, sp	)
+	mov	fpreg, sp
+#endif
 	mov	sp, r2
 	mov	r2, r0
 	mov	r0, r1
 
-	badr	lr, 1f
-	ret	r2
+	bl_r	r2
 
-1:	ldr	lr, [sp]
-	ldr	sp, [sp, #4]
-	ret	lr
+#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
+	ldmdb	fp, {fp, sp, pc}
+#else
+	mov	sp, fpreg
+	pop	{fpreg, pc}
+UNWIND( .fnend			)
+#endif
 ENDPROC(call_with_stack)