On Wed, 23 Sep 2026 09:49:07 -0500
Danish Khateeb <[email protected]> wrote:

> A kprobe single-steps a copy of the probed instruction in
> p->ainsn.insn[]. When the copy is a taken PC-relative branch, its target
> is relative to the copy, and relbranch_fixup() moves it back to the
> probed code. It only recognizes call, BPcc and Bicc, though. For a taken
> BPr (brz, brnz, ...), FBfcc or FBPfcc it keeps the target as is, and the
> kernel continues at the copy's address plus the branch displacement.
> 
> GCC often starts a function with a BPr on an argument. For example,
> __se_sys_getcpu() begins with "brz,pn %o0". With a kprobe on it
> ("p:kprobes/kgetcpu __se_sys_getcpu" in kprobe_events), the first
> getcpu(NULL, NULL, NULL) crashes the kernel in QEMU sun4u:
> 
>   init(1): Kernel illegal instruction [#1]
>   TSTATE: 0000004411001603 TPC: fffff800048d63c0 TNPC: fffff8000492631c
>   Kernel panic - not syncing: Fatal exception
> 
> Add the missing branch formats. BPr is matched with bit 28 clear. The
> CBcond instructions of newer CPUs share its op2 value, but they have no
> delay slot, so a taken one never reaches the single-step breakpoint and
> this function.
> 

Sounds reasonable. From kprobes maintainer point of view:

Acked-by: Masami Hiramatsu (Google) <[email protected]>


Thanks,

> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: [email protected]
> Assisted-by: LLM
> Signed-off-by: Danish Khateeb <[email protected]>
> ---
>  arch/sparc/kernel/kprobes.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c
> index 191bbaca9921..9a26c57c8d33 100644
> --- a/arch/sparc/kernel/kprobes.c
> +++ b/arch/sparc/kernel/kprobes.c
> @@ -207,12 +207,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 with a PC-relative
> +      * displacement.
>        */
> -     if ((insn & 0xc0000000) == 0x40000000 ||
> -         (insn & 0xc1c00000) == 0x00400000 ||
> -         (insn & 0xc1c00000) == 0x00800000) {
> +     if ((insn & 0xc0000000) == 0x40000000 ||        /* call */
> +         (insn & 0xc1c00000) == 0x00400000 ||        /* BPcc */
> +         (insn & 0xc1c00000) == 0x00800000 ||        /* Bicc */
> +         (insn & 0xd1c00000) == 0x00c00000 ||        /* BPr */
> +         (insn & 0xc1c00000) == 0x01400000 ||        /* FBPfcc */
> +         (insn & 0xc1c00000) == 0x01800000) {        /* FBfcc */
>               unsigned long ainsn_addr;
>  
>               ainsn_addr = (unsigned long) &p->ainsn.insn[0];
> -- 
> 2.55.0
> 


-- 
Masami Hiramatsu (Google) <[email protected]>

Reply via email to