Re: [PATCH v12 07/10] arm64: kprobes instruction simulation support

From: Huang Shijie
Date: Wed May 18 2016 - 21:53:18 EST


On Wed, Apr 27, 2016 at 02:53:02PM -0400, David Long wrote:
> From: Sandeepa Prabhu <sandeepa.s.prabhu@xxxxxxxxx>
>
> Kprobes needs simulation of instructions that cannot be stepped
> from a different memory location, e.g.: those instructions
> that uses PC-relative addressing. In simulation, the behaviour
> of the instruction is implemented using a copy of pt_regs.
>
> The following instruction categories are simulated:
> - All branching instructions(conditional, register, and immediate)
> - Literal access instructions(load-literal, adr/adrp)
>
> Conditional execution is limited to branching instructions in
> ARM v8. If conditions at PSTATE do not match the condition fields
> of opcode, the instruction is effectively NOP.
>
> Thanks to Will Cohen for assorted suggested changes.
>
> Signed-off-by: Sandeepa Prabhu <sandeepa.s.prabhu@xxxxxxxxx>
> Signed-off-by: William Cohen <wcohen@xxxxxxxxxx>
> Signed-off-by: David A. Long <dave.long@xxxxxxxxxx>
> ---
> arch/arm64/include/asm/insn.h | 1 +
> arch/arm64/include/asm/probes.h | 5 +-
> arch/arm64/kernel/Makefile | 3 +-
> arch/arm64/kernel/insn.c | 1 +
> arch/arm64/kernel/kprobes-arm64.c | 29 ++++
> arch/arm64/kernel/kprobes.c | 32 ++++-
> arch/arm64/kernel/probes-simulate-insn.c | 218 +++++++++++++++++++++++++++++++
> arch/arm64/kernel/probes-simulate-insn.h | 28 ++++
> 8 files changed, 311 insertions(+), 6 deletions(-)
> create mode 100644 arch/arm64/kernel/probes-simulate-insn.c
> create mode 100644 arch/arm64/kernel/probes-simulate-insn.h
>
> diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
> index b9567a1..26cee10 100644
> --- a/arch/arm64/include/asm/insn.h
> +++ b/arch/arm64/include/asm/insn.h
> @@ -410,6 +410,7 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn);
>
> typedef bool (pstate_check_t)(unsigned long);
> extern pstate_check_t * const opcode_condition_checks[16];
> +
> #endif /* __ASSEMBLY__ */
>
> #endif /* __ASM_INSN_H */
> diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h
> index c5fcbe6..d524f7d 100644
> --- a/arch/arm64/include/asm/probes.h
> +++ b/arch/arm64/include/asm/probes.h
> @@ -15,11 +15,12 @@
> #ifndef _ARM_PROBES_H
> #define _ARM_PROBES_H
>
> +#include <asm/opcodes.h>
> +
> struct kprobe;
> struct arch_specific_insn;
>
> typedef u32 kprobe_opcode_t;
> -typedef unsigned long (kprobes_pstate_check_t)(unsigned long);
> typedef void (kprobes_handler_t) (u32 opcode, long addr, struct pt_regs *);
>
> enum pc_restore_type {
> @@ -35,7 +36,7 @@ struct kprobe_pc_restore {
> /* architecture specific copy of original instruction */
> struct arch_specific_insn {
> kprobe_opcode_t *insn;
> - kprobes_pstate_check_t *pstate_cc;
> + pstate_check_t *pstate_cc;
> kprobes_handler_t *handler;
> /* restore address after step xol */
> struct kprobe_pc_restore restore;
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 8816de2..43bf6cc 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -37,7 +37,8 @@ arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
> arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
> arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
> arm64-obj-$(CONFIG_KGDB) += kgdb.o
> -arm64-obj-$(CONFIG_KPROBES) += kprobes.o kprobes-arm64.o
> +arm64-obj-$(CONFIG_KPROBES) += kprobes.o kprobes-arm64.o \
> + probes-simulate-insn.o
> arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
> arm64-obj-$(CONFIG_PCI) += pci.o
> arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
> index f79e72e..bb2738c 100644
> --- a/arch/arm64/kernel/insn.c
> +++ b/arch/arm64/kernel/insn.c
> @@ -30,6 +30,7 @@
> #include <asm/cacheflush.h>
> #include <asm/debug-monitors.h>
> #include <asm/fixmap.h>
> +#include <asm/opcodes.h>
> #include <asm/insn.h>
>
> #define AARCH64_INSN_SF_BIT BIT(31)
> diff --git a/arch/arm64/kernel/kprobes-arm64.c b/arch/arm64/kernel/kprobes-arm64.c
> index e07727a..487238a 100644
> --- a/arch/arm64/kernel/kprobes-arm64.c
> +++ b/arch/arm64/kernel/kprobes-arm64.c
> @@ -21,6 +21,7 @@
> #include <asm/sections.h>
>
> #include "kprobes-arm64.h"
> +#include "probes-simulate-insn.h"
>
> static bool __kprobes aarch64_insn_is_steppable(u32 insn)
> {
> @@ -62,8 +63,36 @@ arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
> */
> if (aarch64_insn_is_steppable(insn))
> return INSN_GOOD;
> +
> + if (aarch64_insn_is_bcond(insn)) {
> + asi->handler = simulate_b_cond;
> + } else if (aarch64_insn_is_cbz(insn) ||
> + aarch64_insn_is_cbnz(insn)) {
> + asi->handler = simulate_cbz_cbnz;
> + } else if (aarch64_insn_is_tbz(insn) ||
> + aarch64_insn_is_tbnz(insn)) {
> + asi->handler = simulate_tbz_tbnz;
> + } else if (aarch64_insn_is_adr_adrp(insn))
> + asi->handler = simulate_adr_adrp;
> + else if (aarch64_insn_is_b(insn) ||
> + aarch64_insn_is_bl(insn))
> + asi->handler = simulate_b_bl;

For the same codingstyle, we'd better add more "{}" here and below.

thanks
Huang Shijie

> + else if (aarch64_insn_is_br(insn) ||
> + aarch64_insn_is_blr(insn) ||
> + aarch64_insn_is_ret(insn))
> + asi->handler = simulate_br_blr_ret;
> + else if (aarch64_insn_is_ldr_lit(insn))
> + asi->handler = simulate_ldr_literal;
> + else if (aarch64_insn_is_ldrsw_lit(insn))
> + asi->handler = simulate_ldrsw_literal;
> else
> + /*
> + * Instruction cannot be stepped out-of-line and we don't
> + * (yet) simulate it.
> + */
> return INSN_REJECTED;
> +
> + return INSN_GOOD_NO_SLOT;
> }