[PATCH v3 07/13] ARM: unwind: track location of LR value in stack frame
Nick Desaulniers
ndesaulniers at google.com
Mon Feb 7 10:14:13 PST 2022
On Thu, Feb 3, 2022 at 12:22 AM Ard Biesheuvel <ardb at kernel.org> wrote:
>
> The ftrace graph tracer needs to override the return address of an
> instrumented function, in order to install a hook that gets invoked when
> the function returns again.
>
> Currently, we only support this when building for ARM using GCC with
> frame pointers, as in this case, it is guaranteed that the function will
> reload LR from [FP, #-4] in all cases, and we can simply pass that
> address to the ftrace code.
>
> In order to support this for configurations that rely on the EABI
> unwinder, such as Thumb2 builds, make the unwinder keep track of the
> address from which LR was unwound, permitting ftrace to make use of this
> in a subsequent patch.
>
> Drop the call to is_kernel_text_address(), which is problematic in terms
> of ftrace recursion, given that it may be instrumented itself. The call
> is redundant anyway, as no unwind directives will be found unless the PC
> points to memory that is known to contain executable code.
>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
Looks like patch 8/13 consumes lr_addr.
Reviewed-by: Nick Desaulniers <ndesaulniers at google.com>
> ---
> arch/arm/include/asm/stacktrace.h | 3 +++
> arch/arm/kernel/Makefile | 1 +
> arch/arm/kernel/unwind.c | 7 ++++---
> 3 files changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/include/asm/stacktrace.h b/arch/arm/include/asm/stacktrace.h
> index d87d60532b86..e56503fd9447 100644
> --- a/arch/arm/include/asm/stacktrace.h
> +++ b/arch/arm/include/asm/stacktrace.h
> @@ -14,6 +14,9 @@ struct stackframe {
> unsigned long sp;
> unsigned long lr;
> unsigned long pc;
> +
> + /* address of the LR value on the stack */
> + unsigned long *lr_addr;
> #ifdef CONFIG_KRETPROBES
> struct llist_node *kr_cur;
> struct task_struct *tsk;
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index ae295a3bcfef..56511856ff9d 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -10,6 +10,7 @@ ifdef CONFIG_FUNCTION_TRACER
> CFLAGS_REMOVE_ftrace.o = -pg
> CFLAGS_REMOVE_insn.o = -pg
> CFLAGS_REMOVE_patch.o = -pg
> +CFLAGS_REMOVE_unwind.o = -pg
> endif
>
> CFLAGS_REMOVE_return_address.o = -pg
> diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
> index c5ea328c428d..b4e468a7674b 100644
> --- a/arch/arm/kernel/unwind.c
> +++ b/arch/arm/kernel/unwind.c
> @@ -55,6 +55,7 @@ struct unwind_ctrl_block {
> const unsigned long *insn; /* pointer to the current instructions word */
> unsigned long sp_low; /* lowest value of sp allowed */
> unsigned long sp_high; /* highest value of sp allowed */
> + unsigned long *lr_addr; /* address of LR value on the stack */
> /*
> * 1 : check for stack overflow for each register pop.
> * 0 : save overhead if there is plenty of stack remaining.
> @@ -239,6 +240,8 @@ static int unwind_pop_register(struct unwind_ctrl_block *ctrl,
> * from being tracked by KASAN.
> */
> ctrl->vrs[reg] = READ_ONCE_NOCHECK(*(*vsp));
> + if (reg == 14)
> + ctrl->lr_addr = *vsp;
> (*vsp)++;
> return URC_OK;
> }
> @@ -395,9 +398,6 @@ int unwind_frame(struct stackframe *frame)
> pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
> frame->pc, frame->lr, frame->sp);
>
> - if (!kernel_text_address(frame->pc))
> - return -URC_FAILURE;
> -
> idx = unwind_find_idx(frame->pc);
> if (!idx) {
> pr_warn("unwind: Index not found %08lx\n", frame->pc);
> @@ -476,6 +476,7 @@ int unwind_frame(struct stackframe *frame)
> frame->lr = ctrl.vrs[LR];
> frame->pc = ctrl.vrs[PC];
> frame->sp_low = ctrl.sp_low;
> + frame->lr_addr = ctrl.lr_addr;
>
> return URC_OK;
> }
> --
> 2.30.2
>
--
Thanks,
~Nick Desaulniers
More information about the linux-arm-kernel
mailing list