[PATCH v2 09/12] ARM: kprobes: treat R7 as the frame pointer register in Thumb2 builds
Masami Hiramatsu
mhiramat at kernel.org
Tue Feb 1 05:18:39 PST 2022
On Mon, 31 Jan 2022 18:03:44 +0100
Ard Biesheuvel <ardb at kernel.org> wrote:
> Thumb2 code uses R7 as the frame pointer rather than R11, because the
> opcodes to access it are generally shorter.
>
> This means that there are cases where we cannot simply add it to the
> clobber list of an asm() block, but need to preserve/restore it
> explicitly, or the compiler may complain in some cases (e.g., Clang
> builds with ftrace enabled).
>
> Since R11 is not special in that case, clobber it instead, and use it to
> preserve/restore the value of R7.
Thanks Ard for fixing thumb2 issue!
BTW, have you build the kernel with CONFIG_KPROBES_SANITY_TEST=y?
It should check the backtrace from kprobe and kretprobe at boot time.
Thank you,
>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
> arch/arm/include/asm/opcodes.h | 14 ++++++++
> arch/arm/probes/kprobes/actions-common.c | 6 ++--
> arch/arm/probes/kprobes/actions-thumb.c | 38 ++++++++++++++++----
> 3 files changed, 48 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/include/asm/opcodes.h b/arch/arm/include/asm/opcodes.h
> index 38e3eabff5c3..9a6362408ea0 100644
> --- a/arch/arm/include/asm/opcodes.h
> +++ b/arch/arm/include/asm/opcodes.h
> @@ -230,4 +230,18 @@ extern __u32 __opcode_to_mem_thumb32(__u32);
> ".short " __stringify(first) ", " __stringify(second) "\n\t"
> #endif
>
> +/*
> + * Which register to preserve and which register can be clobbered in inline asm
> + * that needs to be compatible with code that emits frame pointers.
> + */
> +#ifdef CONFIG_THUMB2_KERNEL
> +#define FPREG_PRESERVE "r7"
> +#define FPREG_CLOBBER "r11"
> +#define FPREG_PRESERVE_R7
> +#else
> +#define FPREG_PRESERVE "fp"
> +#define FPREG_CLOBBER "r7"
> +#define FPREG_PRESERVE_R11
> +#endif
> +
> #endif /* __ASM_ARM_OPCODES_H */
> diff --git a/arch/arm/probes/kprobes/actions-common.c b/arch/arm/probes/kprobes/actions-common.c
> index 836aebe596cd..f0efe16e2fdb 100644
> --- a/arch/arm/probes/kprobes/actions-common.c
> +++ b/arch/arm/probes/kprobes/actions-common.c
> @@ -84,7 +84,7 @@ emulate_generic_r0_12_noflags(probes_opcode_t insn,
> register void *rfn asm("lr") = asi->insn_fn;
>
> __asm__ __volatile__ (
> - "stmdb sp!, {%[regs], r11} \n\t"
> + "stmdb sp!, {%[regs], " FPREG_PRESERVE "}\n\t"
> "ldmia %[regs], {r0-r12} \n\t"
> #if __LINUX_ARM_ARCH__ >= 6
> "blx %[fn] \n\t"
> @@ -96,10 +96,10 @@ emulate_generic_r0_12_noflags(probes_opcode_t insn,
> #endif
> "ldr lr, [sp], #4 \n\t" /* lr = regs */
> "stmia lr, {r0-r12} \n\t"
> - "ldr r11, [sp], #4 \n\t"
> + "ldr " FPREG_PRESERVE ", [sp], #4\n\t"
> : [regs] "=r" (rregs), [fn] "=r" (rfn)
> : "0" (rregs), "1" (rfn)
> - : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
> + : "r0", "r2", "r3", "r4", "r5", "r6", FPREG_CLOBBER,
> "r8", "r9", "r10", "r12", "memory", "cc"
> );
> }
> diff --git a/arch/arm/probes/kprobes/actions-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
> index 7884fcb81c26..873757326533 100644
> --- a/arch/arm/probes/kprobes/actions-thumb.c
> +++ b/arch/arm/probes/kprobes/actions-thumb.c
> @@ -447,14 +447,20 @@ t16_emulate_loregs(probes_opcode_t insn,
>
> __asm__ __volatile__ (
> "msr cpsr_fs, %[oldcpsr] \n\t"
> +#ifdef FPREG_PRESERVE_R7
> + "mov fp, r7 \n\t"
> +#endif
> "ldmia %[regs], {r0-r7} \n\t"
> "blx %[fn] \n\t"
> "stmia %[regs], {r0-r7} \n\t"
> +#ifdef FPREG_PRESERVE_R7
> + "mov r7, fp \n\t"
> +#endif
> "mrs %[newcpsr], cpsr \n\t"
> : [newcpsr] "=r" (newcpsr)
> : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
> [fn] "r" (asi->insn_fn)
> - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
> + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", FPREG_CLOBBER,
> "lr", "memory", "cc"
> );
>
> @@ -524,15 +530,21 @@ t16_emulate_push(probes_opcode_t insn,
> struct arch_probes_insn *asi, struct pt_regs *regs)
> {
> __asm__ __volatile__ (
> +#ifdef FPREG_PRESERVE_R7
> + "mov fp, r7 \n\t"
> +#endif
> "ldr r9, [%[regs], #13*4] \n\t"
> "ldr r8, [%[regs], #14*4] \n\t"
> "ldmia %[regs], {r0-r7} \n\t"
> "blx %[fn] \n\t"
> "str r9, [%[regs], #13*4] \n\t"
> +#ifdef FPREG_PRESERVE_R7
> + "mov r7, fp \n\t"
> +#endif
> :
> : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
> - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
> - "lr", "memory", "cc"
> + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9",
> + FPREG_CLOBBER, "lr", "memory", "cc"
> );
> }
>
> @@ -558,15 +570,21 @@ t16_emulate_pop_nopc(probes_opcode_t insn,
> struct arch_probes_insn *asi, struct pt_regs *regs)
> {
> __asm__ __volatile__ (
> +#ifdef FPREG_PRESERVE_R7
> + "mov fp, r7 \n\t"
> +#endif
> "ldr r9, [%[regs], #13*4] \n\t"
> "ldmia %[regs], {r0-r7} \n\t"
> "blx %[fn] \n\t"
> "stmia %[regs], {r0-r7} \n\t"
> "str r9, [%[regs], #13*4] \n\t"
> +#ifdef FPREG_PRESERVE_R7
> + "mov r7, fp \n\t"
> +#endif
> :
> : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
> - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
> - "lr", "memory", "cc"
> + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9",
> + FPREG_CLOBBER, "lr", "memory", "cc"
> );
> }
>
> @@ -577,15 +595,21 @@ t16_emulate_pop_pc(probes_opcode_t insn,
> register unsigned long pc asm("r8");
>
> __asm__ __volatile__ (
> +#ifdef FPREG_PRESERVE_R7
> + "mov fp, r7 \n\t"
> +#endif
> "ldr r9, [%[regs], #13*4] \n\t"
> "ldmia %[regs], {r0-r7} \n\t"
> "blx %[fn] \n\t"
> "stmia %[regs], {r0-r7} \n\t"
> "str r9, [%[regs], #13*4] \n\t"
> +#ifdef FPREG_PRESERVE_R7
> + "mov r7, fp \n\t"
> +#endif
> : "=r" (pc)
> : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
> - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
> - "lr", "memory", "cc"
> + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9",
> + FPREG_CLOBBER, "lr", "memory", "cc"
> );
>
> bx_write_pc(pc, regs);
> --
> 2.30.2
>
--
Masami Hiramatsu <mhiramat at kernel.org>
More information about the linux-arm-kernel
mailing list