diff options
author | Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> | 2017-09-15 15:38:21 +0530 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-09-20 20:21:24 +1000 |
commit | 8afafa6fba7809c0785018b77c95b19e58b35b94 (patch) | |
tree | 81d6e4a689023221cfa7cdcc5c94e85e67e14fc9 /arch/powerpc/kernel | |
parent | b134165eadd6dd07c49f8db40b218185ca3130b0 (diff) |
powerpc/kprobes: Update optprobes to use emulate_update_regs()
Optprobes depended on an updated regs->nip from analyse_instr() to
identify the location to branch back from the optprobes trampoline.
However, since commit 3cdfcbfd32b9d ("powerpc: Change analyse_instr so
it doesn't modify *regs"), analyse_instr() doesn't update the registers
anymore. Due to this, we end up branching back from the optprobes
trampoline to the same branch into the trampoline resulting in a loop.
Fix this by calling out to emulate_update_regs() before using the nip.
Additionally, explicitly compare the return value from analyse_instr()
to 1, rather than just checking for !0 so as to guard against any
future changes to analyse_instr() that may result in -1 being returned
in more scenarios.
Fixes: 3cdfcbfd32b9d ("powerpc: Change analyse_instr so it doesn't modify *regs")
Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/optprobes.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/optprobes.c b/arch/powerpc/kernel/optprobes.c index 6f8273f5e988..91e037ab20a1 100644 --- a/arch/powerpc/kernel/optprobes.c +++ b/arch/powerpc/kernel/optprobes.c @@ -104,8 +104,10 @@ static unsigned long can_optimize(struct kprobe *p) * and that can be emulated. */ if (!is_conditional_branch(*p->ainsn.insn) && - analyse_instr(&op, ®s, *p->ainsn.insn)) + analyse_instr(&op, ®s, *p->ainsn.insn) == 1) { + emulate_update_regs(®s, &op); nip = regs.nip; + } return nip; } |