relbranch_fixup() moves the target of a PC-relative branch from the single-step slot back to the probed instruction, but it only knows call, Bicc and BPcc. A taken BPr (brz, brnz, ...) or FBPfcc/FBfcc is taken for an absolute jump, and execution resumes at the target relative to the slot:
Unable to handle kernel paging request at virtual address 000000000fffff98 TPC: <0xfffff98> Treat them like the other PC-relative branches. Link: https://github.com/sparclinux/issues/issues/110 Signed-off-by: Stian Halseth <[email protected]> --- arch/sparc/kernel/kprobes.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index 608efda8cb948..38e6d9b51a207 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -219,12 +219,15 @@ static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p, if (regs->tnpc == regs->tpc + 0x4UL) return real_pc + 0x8UL; - /* The three cases are call, branch w/prediction, - * and traditional branch. + /* The cases are call and the branches BPcc, Bicc, BPr, FBPfcc + * and FBfcc. */ if ((insn & 0xc0000000) == 0x40000000 || (insn & 0xc1c00000) == 0x00400000 || - (insn & 0xc1c00000) == 0x00800000) { + (insn & 0xc1c00000) == 0x00800000 || + (insn & 0xc1c00000) == 0x00c00000 || + (insn & 0xc1c00000) == 0x01400000 || + (insn & 0xc1c00000) == 0x01800000) { unsigned long ainsn_addr; ainsn_addr = (unsigned long) &p->ainsn.insn[0]; -- 2.43.0
