summaryrefslogtreecommitdiff
path: root/arch/arm/kernel/unwind.c
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2022-01-24 16:49:09 +0100
committerArd Biesheuvel <ardb@kernel.org>2022-02-09 09:13:43 +0100
commit538b9265c063f081ca6b1228d242575a1db60711 (patch)
treebefdd399f7bf56691bf58e7fb09bbd3107cddb46 /arch/arm/kernel/unwind.c
parent953f534a7ed6b725d4f101d2949393acc9262880 (diff)
ARM: unwind: track location of LR value in stack frame
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@kernel.org> Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Diffstat (limited to 'arch/arm/kernel/unwind.c')
-rw-r--r--arch/arm/kernel/unwind.c7
1 files changed, 4 insertions, 3 deletions
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;
}