arm64: kprobes instruction simulation support

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@gmail.com>
Signed-off-by: William Cohen <wcohen@redhat.com>
Signed-off-by: David A. Long <dave.long@linaro.org>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
[catalin.marinas@arm.com: removed linux/module.h include]
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
Sandeepa Prabhu
2016-07-08 12:35:51 -04:00
committed by Catalin Marinas
szülő 888b3c8720
commit 39a67d49ba
8 fájl változott, egészen pontosan 326 új sor hozzáadva és 15 régi sor törölve

Fájl megtekintése

@@ -45,6 +45,9 @@ void jprobe_return_break(void);
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
static void __kprobes
post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
{
/* prepare insn slot */
@@ -61,6 +64,23 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
sizeof(kprobe_opcode_t);
}
static void __kprobes arch_prepare_simulate(struct kprobe *p)
{
/* This instructions is not executed xol. No need to adjust the PC */
p->ainsn.restore = 0;
}
static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
{
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (p->ainsn.handler)
p->ainsn.handler((u32)p->opcode, (long)p->addr, regs);
/* single step simulated, now go for post processing */
post_kprobe_handler(kcb, regs);
}
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
unsigned long probe_addr = (unsigned long)p->addr;
@@ -84,6 +104,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
case INSN_REJECTED: /* insn not supported */
return -EINVAL;
case INSN_GOOD_NO_SLOT: /* insn need simulation */
p->ainsn.insn = NULL;
break;
case INSN_GOOD: /* instruction uses slot */
p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn)
@@ -92,7 +116,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
};
/* prepare the instruction */
arch_prepare_ss_slot(p);
if (p->ainsn.insn)
arch_prepare_ss_slot(p);
else
arch_prepare_simulate(p);
return 0;
}
@@ -218,20 +245,24 @@ static void __kprobes setup_singlestep(struct kprobe *p,
kcb->kprobe_status = KPROBE_HIT_SS;
}
BUG_ON(!p->ainsn.insn);
/* prepare for single stepping */
slot = (unsigned long)p->ainsn.insn;
if (p->ainsn.insn) {
/* prepare for single stepping */
slot = (unsigned long)p->ainsn.insn;
set_ss_context(kcb, slot); /* mark pending ss */
set_ss_context(kcb, slot); /* mark pending ss */
if (kcb->kprobe_status == KPROBE_REENTER)
spsr_set_debug_flag(regs, 0);
if (kcb->kprobe_status == KPROBE_REENTER)
spsr_set_debug_flag(regs, 0);
/* IRQs and single stepping do not mix well. */
kprobes_save_local_irqflag(kcb, regs);
kernel_enable_single_step(regs);
instruction_pointer_set(regs, slot);
/* IRQs and single stepping do not mix well. */
kprobes_save_local_irqflag(kcb, regs);
kernel_enable_single_step(regs);
instruction_pointer_set(regs, slot);
} else {
/* insn simulation */
arch_simulate_insn(p, regs);
}
}
static int __kprobes reenter_kprobe(struct kprobe *p,