AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/06/23 19:43 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_JIT",
    "FUNCTION_TRACER"
  ],
  "FocusSymbols": [
    "bpf_int_jit_compile",
    "bpf_jit_build_fentry_stubs",
    "bpf_jit_emit_exit_insn",
    "bpf_jit_build_epilogue",
    "bpf_jit_build_body",
    "bpf_jit_build_prologue",
    "bpf_jit_emit_tail_call",
    "bpf_trampoline_setup_tail_call_info",
    "bpf_arch_text_poke"
  ],
  "Reasoning": "The patch modifies the BPF JIT compiler for PowerPC, specifically adjusting the code generation passes, fentry stubs alignment, and epilogue/exit instructions. These changes affect how BPF programs are compiled and executed on PowerPC architectures. Fuzzing the BPF JIT compiler on PowerPC will help ensure the correctness of the generated machine code and prevent potential crashes or vulnerabilities.",
  "WorthFuzzing": true
}

1/1 2026/06/23 19:43 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit ee6a5643b9bb753aea7521ef52e8479d4f20777b\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Tue Jun 23 19:43:20 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h\nindex f32de8704d4d96..4da8bde92e1eff 100644\n--- a/arch/powerpc/net/bpf_jit.h\n+++ b/arch/powerpc/net/bpf_jit.h\n@@ -14,6 +14,13 @@\n #include \u003casm/ppc-opcode.h\u003e\n #include \u003clinux/build_bug.h\u003e\n \n+/*\n+ * We need at least 2 passes for proper code generation, and may need\n+ * additional passes if code size changes between passes.\n+ */\n+#define CODEGEN_MIN_PASSES    2\n+#define CODEGEN_MAX_PASSES    3\n+\n #ifdef CONFIG_PPC64_ELF_ABI_V1\n #define FUNCTION_DESCR_SIZE\t24\n #else\n@@ -188,6 +195,12 @@ struct codegen_context {\n \n #define bpf_to_ppc(r)\t(ctx-\u003eb2p[r])\n \n+#ifdef CONFIG_PPC64\n+#define PPC_RAW_CMPLLI(a, i)    PPC_RAW_CMPLDI(a, i)\n+#else\n+#define PPC_RAW_CMPLLI(a, i)    PPC_RAW_CMPLWI(a, i)\n+#endif\n+\n #ifdef CONFIG_PPC32\n #define BPF_FIXUP_LEN\t3 /* Three instructions =\u003e 12 bytes */\n #else\n@@ -214,10 +227,11 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *\n int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,\n \t\t       u32 *addrs, int pass, bool extra_pass);\n void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);\n-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);\n-void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx);\n+void bpf_jit_build_epilogue(u32 *image, u32 *fimage, struct codegen_context *ctx);\n+void bpf_jit_build_fentry_stubs(u32 *image, u32 *fimage, struct codegen_context *ctx);\n void bpf_jit_realloc_regs(struct codegen_context *ctx);\n-int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr);\n+int bpf_jit_emit_exit_insn(u32 *image, u32 *fimage, struct codegen_context *ctx, int tmp_reg,\n+\t\t\t\t\t\t\t\t\t\tlong exit_addr);\n void prepare_for_fsession_fentry(u32 *image, struct codegen_context *ctx, int cookie_cnt,\n \t\t\t\t\t\t\t\tint cookie_off, int retval_off);\n void store_func_meta(u32 *image, struct codegen_context *ctx, u64 func_meta, int func_meta_off);\ndiff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c\nindex 6351a187ca61e2..46bbfb6be61340 100644\n--- a/arch/powerpc/net/bpf_jit_comp.c\n+++ b/arch/powerpc/net/bpf_jit_comp.c\n@@ -49,11 +49,37 @@ asm (\n \"\t.popsection\t\t\t\t;\"\n );\n \n-void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx)\n+void bpf_jit_build_fentry_stubs(u32 *image, u32 *fimage, struct codegen_context *ctx)\n {\n \tint ool_stub_idx, long_branch_stub_idx;\n+\tint stub_sz;\n \n \t/*\n+\t * The dummy_tramp_addr field is placed at bottom of Long branch stub.\n+\t * In the final pass, align the mis-aligned dummy_tramp_addr field\n+\t * in the fimage. The alignment NOP must appear before OOL stub,\n+\t * to make ool_stub_idx \u0026 long_branch_stub_idx constant from end.\n+\t *\n+\t * dummy_tramp_addr must be 8-byte aligned for load-register\n+\t * compatibility. The fimage can be non 8-byte aligned, so final\n+\t * alignment depends on start of fimage and the stub's instruction\n+\t * count. The stubs block has 11 instructions (with\n+\t * CONFIG_PPC_FTRACE_OUT_OF_LINE) or 10 instructions (without)\n+\t * before dummy_tramp_addr field. Emit a NOP if the address of\n+\t * dummy_tramp_addr is non aligned.\n+\t *\n+\t * In pass=0 when image==NULL, conservatively account for space\n+\t * required to accommodate alignment NOP. In case final pass skips\n+\t * emitting alignment NOP, the image buffer have 4 spare bytes and\n+\t * jited_len signifies correct program size.\n+\t */\n+\n+\tstub_sz = IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) ? 44 : 40;\n+\tif (!image || !IS_ALIGNED((unsigned long)fimage + ctx-\u003eidx*4 + stub_sz, SZL))\n+\t\tEMIT(PPC_RAW_NOP());\n+\n+\t/*\n+\t *      nop     // optional, for alignment of dummy_tramp_addr\n \t * Out-of-line stub:\n \t *\tmflr\tr0\n \t *\t[b|bl]\ttramp\n@@ -70,44 +96,46 @@ void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx)\n \n \t/*\n \t * Long branch stub:\n-\t *\t.long\t\u003cdummy_tramp_addr\u003e\n \t *\tmflr\tr11\n \t *\tbcl\t20,31,$+4\n-\t *\tmflr\tr12\n-\t *\tld\tr12, -8-SZL(r12)\n+\t *\tmflr\tr12\t// lr/r12 stores pc of current(this) inst.\n+\t *\tld\tr12, 20(r12) // offset(dummy_tramp_addr) from prev inst. is 20\n \t *\tmtctr\tr12\n-\t *\tmtlr\tr11 // needed to retain ftrace ABI\n+\t *\tmtlr\tr11\t// needed to retain ftrace ABI\n \t *\tbctr\n+\t *\t.long\t\u003cdummy_tramp_addr\u003e  // 8-byte aligned\n \t */\n-\tif (image)\n-\t\t*((unsigned long *)\u0026image[ctx-\u003eidx]) = (unsigned long)dummy_tramp;\n-\tctx-\u003eidx += SZL / 4;\n \tlong_branch_stub_idx = ctx-\u003eidx;\n \tEMIT(PPC_RAW_MFLR(_R11));\n \tEMIT(PPC_RAW_BCL4());\n \tEMIT(PPC_RAW_MFLR(_R12));\n-\tEMIT(PPC_RAW_LL(_R12, _R12, -8-SZL));\n+\tEMIT(PPC_RAW_LL(_R12, _R12, 20));\n \tEMIT(PPC_RAW_MTCTR(_R12));\n \tEMIT(PPC_RAW_MTLR(_R11));\n \tEMIT(PPC_RAW_BCTR());\n \n+\tif (image)\n+\t\t*((unsigned long *)\u0026image[ctx-\u003eidx]) = (unsigned long)dummy_tramp;\n+\n+\tctx-\u003eidx += SZL / 4;\n+\n \tif (!bpf_jit_ool_stub) {\n \t\tbpf_jit_ool_stub = (ctx-\u003eidx - ool_stub_idx) * 4;\n \t\tbpf_jit_long_branch_stub = (ctx-\u003eidx - long_branch_stub_idx) * 4;\n \t}\n }\n \n-int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr)\n+int bpf_jit_emit_exit_insn(u32 *image, u32 *fimage, struct codegen_context *ctx,\n+\t\t\t\t\t\t\tint tmp_reg, long exit_addr)\n {\n-\tif (!exit_addr || is_offset_in_branch_range(exit_addr - (ctx-\u003eidx * 4))) {\n+\tif (exit_addr \u0026\u0026 is_offset_in_branch_range(exit_addr - (long)(ctx-\u003eidx * 4))) {\n \t\tPPC_JMP(exit_addr);\n-\t} else if (ctx-\u003ealt_exit_addr) {\n-\t\tif (WARN_ON(!is_offset_in_branch_range((long)ctx-\u003ealt_exit_addr - (ctx-\u003eidx * 4))))\n-\t\t\treturn -1;\n+\t} else if (ctx-\u003ealt_exit_addr \u0026\u0026 is_offset_in_branch_range(\n+\t\t\t(long)(ctx-\u003ealt_exit_addr) - (long)(ctx-\u003eidx * 4))) {\n \t\tPPC_JMP(ctx-\u003ealt_exit_addr);\n \t} else {\n \t\tctx-\u003ealt_exit_addr = ctx-\u003eidx * 4;\n-\t\tbpf_jit_build_epilogue(image, ctx);\n+\t\tbpf_jit_build_epilogue(image, fimage, ctx);\n \t}\n \n \treturn 0;\n@@ -274,6 +302,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr\n \t */\n \tif (cgctx.seen \u0026 SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {\n \t\tcgctx.idx = 0;\n+\t\tcgctx.alt_exit_addr = 0;\n \t\tif (bpf_jit_build_body(fp, NULL, NULL, \u0026cgctx, addrs, 0, false))\n \t\t\tgoto out_err;\n \t}\n@@ -286,7 +315,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr\n \t */\n \tbpf_jit_build_prologue(NULL, \u0026cgctx);\n \taddrs[fp-\u003elen] = cgctx.idx * 4;\n-\tbpf_jit_build_epilogue(NULL, \u0026cgctx);\n+\tbpf_jit_build_epilogue(NULL, NULL, \u0026cgctx);\n \n \tfixup_len = fp-\u003eaux-\u003enum_exentries * BPF_FIXUP_LEN * 4;\n \textable_len = fp-\u003eaux-\u003enum_exentries * sizeof(struct exception_table_entry);\n@@ -306,8 +335,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr\n \tcode_base = (u32 *)(image + FUNCTION_DESCR_SIZE);\n \tfcode_base = (u32 *)(fimage + FUNCTION_DESCR_SIZE);\n \n-\t/* Code generation passes 1-2 */\n-\tfor (pass = 1; pass \u003c 3; pass++) {\n+\t/* Code generation passes 1-2+, loop until program size converges. */\n+\tfor (pass = 1; pass \u003c= CODEGEN_MAX_PASSES; pass++) {\n+\t\tu32 prev_proglen = proglen;\n+\n \t\t/* Now build the prologue, body code \u0026 epilogue for real. */\n \t\tcgctx.idx = 0;\n \t\tcgctx.alt_exit_addr = 0;\n@@ -318,11 +349,26 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr\n \t\t\tbpf_jit_binary_pack_free(fhdr, hdr);\n \t\t\tgoto out_err;\n \t\t}\n-\t\tbpf_jit_build_epilogue(code_base, \u0026cgctx);\n+\t\taddrs[fp-\u003elen] = cgctx.idx * 4;\n+\t\tbpf_jit_build_epilogue(code_base, fcode_base, \u0026cgctx);\n+\n+\t\tproglen = cgctx.idx * 4;\n \n \t\tif (bpf_jit_enable \u003e 1)\n \t\t\tpr_info(\"Pass %d: shrink = %d, seen = 0x%x\\n\", pass,\n-\t\t\t\tproglen - (cgctx.idx * 4), cgctx.seen);\n+\t\t\t\tprev_proglen - proglen, cgctx.seen);\n+\n+\t\t/* Check if program size has converged, but ensure minimum passes */\n+\t\tif (pass \u003e= CODEGEN_MIN_PASSES \u0026\u0026 proglen == prev_proglen)\n+\t\t\tbreak;\n+\n+\t\tif (pass == CODEGEN_MAX_PASSES \u0026\u0026 proglen != prev_proglen) {\n+\t\t\tpr_err(\"BPF JIT: Program did not converge after %d passes\\n\",\n+\t\t\t\t\t\t\t\tCODEGEN_MAX_PASSES);\n+\t\t\tbpf_arch_text_copy(\u0026fhdr-\u003esize, \u0026hdr-\u003esize, sizeof(hdr-\u003esize));\n+\t\t\tbpf_jit_binary_pack_free(fhdr, hdr);\n+\t\t\tgoto out_err;\n+\t\t}\n \t}\n \n \tif (bpf_jit_enable \u003e 1)\n@@ -357,7 +403,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr\n \t\t\t\t(void *)fimage + FUNCTION_DESCR_SIZE);\n \n out_addrs:\n-\t\tif (!image \u0026\u0026 priv_stack_ptr) {\n+\t\tif (!fp-\u003ejited \u0026\u0026 priv_stack_ptr) {\n \t\t\tfp-\u003eaux-\u003epriv_stack_ptr = NULL;\n \t\t\tfree_percpu(priv_stack_ptr);\n \t\t}\n@@ -734,7 +780,7 @@ static void bpf_trampoline_setup_tail_call_info(u32 *image, struct codegen_conte\n \t\t * Setting the tail_call_info in trampoline's frame\n \t\t * depending on if previous frame had value or reference.\n \t\t */\n-\t\tEMIT(PPC_RAW_CMPLWI(_R3, MAX_TAIL_CALL_CNT));\n+\t\tEMIT(PPC_RAW_CMPLLI(_R3, MAX_TAIL_CALL_CNT));\n \t\tPPC_BCC_CONST_SHORT(COND_GT, 8);\n \t\tEMIT(PPC_RAW_ADDI(_R3, _R4, -BPF_PPC_TAILCALL));\n \n@@ -1260,6 +1306,7 @@ static void do_isync(void *info __maybe_unused)\n  * bpf_func:\n  *\t[nop|b]\tool_stub\n  * 2. Out-of-line stub:\n+ *\tnop\t// optional nop for alignment\n  * ool_stub:\n  *\tmflr\tr0\n  *\t[b|bl]\t\u003cbpf_prog\u003e/\u003clong_branch_stub\u003e\n@@ -1267,14 +1314,14 @@ static void do_isync(void *info __maybe_unused)\n  *\tb\tbpf_func + 4\n  * 3. Long branch stub:\n  * long_branch_stub:\n- *\t.long\t\u003cbranch_addr\u003e/\u003cdummy_tramp\u003e\n  *\tmflr\tr11\n  *\tbcl\t20,31,$+4\n  *\tmflr\tr12\n- *\tld\tr12, -16(r12)\n+ *\tld\tr12, 20(r12)\n  *\tmtctr\tr12\n  *\tmtlr\tr11 // needed to retain ftrace ABI\n  *\tbctr\n+ *\t.long\t\u003cbranch_addr\u003e/\u003cdummy_tramp\u003e\n  *\n  * dummy_tramp is used to reduce synchronization requirements.\n  *\n@@ -1376,10 +1423,12 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,\n \t * 1. Update the address in the long branch stub:\n \t * If new_addr is out of range, we will have to use the long branch stub, so patch new_addr\n \t * here. Otherwise, revert to dummy_tramp, but only if we had patched old_addr here.\n+\t *\n+\t * dummy_tramp_addr moved to bottom of long branch stub.\n \t */\n \tif ((new_addr \u0026\u0026 !is_offset_in_branch_range(new_addr - ip)) ||\n \t    (old_addr \u0026\u0026 !is_offset_in_branch_range(old_addr - ip)))\n-\t\tret = patch_ulong((void *)(bpf_func_end - bpf_jit_long_branch_stub - SZL),\n+\t\tret = patch_ulong((void *)(bpf_func_end - SZL), /* SZL: dummy_tramp_addr offset */\n \t\t\t\t  (new_addr \u0026\u0026 !is_offset_in_branch_range(new_addr - ip)) ?\n \t\t\t\t  (unsigned long)new_addr : (unsigned long)dummy_tramp);\n \tif (ret)\ndiff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c\nindex bfdc50740da8e7..f5b9441cf46aa7 100644\n--- a/arch/powerpc/net/bpf_jit_comp32.c\n+++ b/arch/powerpc/net/bpf_jit_comp32.c\n@@ -229,7 +229,7 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx\n \n }\n \n-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)\n+void bpf_jit_build_epilogue(u32 *image, u32 *fimage, struct codegen_context *ctx)\n {\n \tEMIT(PPC_RAW_MR(_R3, bpf_to_ppc(BPF_REG_0)));\n \n@@ -237,7 +237,7 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)\n \n \tEMIT(PPC_RAW_BLR());\n \n-\tbpf_jit_build_fentry_stubs(image, ctx);\n+\tbpf_jit_build_fentry_stubs(image, fimage, ctx);\n }\n \n /* Relative offset needs to be calculated based on final image location */\n@@ -1149,7 +1149,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code\n \t\t\t * we'll just fall through to the epilogue.\n \t\t\t */\n \t\t\tif (i != flen - 1) {\n-\t\t\t\tret = bpf_jit_emit_exit_insn(image, ctx, _R0, exit_addr);\n+\t\t\t\tret = bpf_jit_emit_exit_insn(image, fimage,\n+\t\t\t\t\t\t\t\tctx, _R0, exit_addr);\n \t\t\t\tif (ret)\n \t\t\t\t\treturn ret;\n \t\t\t}\ndiff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c\nindex db364d9083e725..086084abb184a4 100644\n--- a/arch/powerpc/net/bpf_jit_comp64.c\n+++ b/arch/powerpc/net/bpf_jit_comp64.c\n@@ -276,7 +276,7 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)\n \t\t */\n \t\tEMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_2), _R1, 0));\n \t\tEMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_2), -(BPF_PPC_TAILCALL)));\n-\t\tEMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));\n+\t\tEMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));\n \t\tPPC_BCC_CONST_SHORT(COND_GT, 8);\n \t\tEMIT(PPC_RAW_ADDI(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_2),\n \t\t\t\t\t\t\t\t-(BPF_PPC_TAILCALL)));\n@@ -398,7 +398,7 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx\n \t}\n }\n \n-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)\n+void bpf_jit_build_epilogue(u32 *image, u32 *fimage, struct codegen_context *ctx)\n {\n \tbpf_jit_emit_common_epilogue(image, ctx);\n \n@@ -407,7 +407,7 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)\n \n \tEMIT(PPC_RAW_BLR());\n \n-\tbpf_jit_build_fentry_stubs(image, ctx);\n+\tbpf_jit_build_fentry_stubs(image, fimage, ctx);\n }\n \n /*\n@@ -651,7 +651,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o\n \tPPC_BCC_SHORT(COND_GE, out);\n \n \tEMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), _R1, bpf_jit_stack_tailcallinfo_offset(ctx)));\n-\tEMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));\n+\tEMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));\n \tPPC_BCC_CONST_SHORT(COND_LE, 8);\n \n \t/* dereference TMP_REG_1 */\n@@ -661,7 +661,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o\n \t * if (tail_call_info == MAX_TAIL_CALL_CNT)\n \t *   goto out;\n \t */\n-\tEMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));\n+\tEMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));\n \tPPC_BCC_SHORT(COND_EQ, out);\n \n \t/*\n@@ -696,7 +696,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o\n \t * tail_call_info.\n \t */\n \tEMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_2), _R1, bpf_jit_stack_tailcallinfo_offset(ctx)));\n-\tEMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_2), MAX_TAIL_CALL_CNT));\n+\tEMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_2), MAX_TAIL_CALL_CNT));\n \tPPC_BCC_CONST_SHORT(COND_GT, 8);\n \n \t/* First get address of tail_call_info */\n@@ -1726,7 +1726,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code\n \t\t\t * we'll just fall through to the epilogue.\n \t\t\t */\n \t\t\tif (i != flen - 1) {\n-\t\t\t\tret = bpf_jit_emit_exit_insn(image, ctx, tmp1_reg, exit_addr);\n+\t\t\t\tret = bpf_jit_emit_exit_insn(image, fimage, ctx,\n+\t\t\t\t\t\t\t\ttmp1_reg, exit_addr);\n \t\t\t\tif (ret)\n \t\t\t\t\treturn ret;\n \t\t\t}\ndiff --git a/tools/testing/selftests/bpf/jit_disasm_helpers.c b/tools/testing/selftests/bpf/jit_disasm_helpers.c\nindex 3558fe10e28cf9..11428cad5b2d2b 100644\n--- a/tools/testing/selftests/bpf/jit_disasm_helpers.c\n+++ b/tools/testing/selftests/bpf/jit_disasm_helpers.c\n@@ -178,10 +178,12 @@ int get_jited_program_text(int fd, char *text, size_t text_sz)\n {\n \tstruct bpf_prog_info info = {};\n \t__u32 info_len = sizeof(info);\n-\t__u32 jited_funcs, len, pc;\n+\t__u32 jited_funcs, len, pc, disasm_len;\n+\t__u32 trunc_len = 0;\n \t__u32 *func_lens = NULL;\n \tFILE *text_out = NULL;\n \tuint8_t *image = NULL;\n+\tchar *triple = NULL;\n \tint i, err = 0;\n \n \tif (!llvm_initialized) {\n@@ -225,9 +227,30 @@ int get_jited_program_text(int fd, char *text, size_t text_sz)\n \tif (!ASSERT_OK(err, \"bpf_prog_get_info_by_fd #2\"))\n \t\tgoto out;\n \n+\t/*\n+\t * last 8 bytes contains dummy_trampoline address in JIT\n+\t * output on 64-bit and last 4 bytes on 32-bit powerpc,\n+\t * which can't disassemble to a valid instruction.\n+\t */\n+\ttriple = LLVMGetDefaultTargetTriple();\n+\tif (triple) {\n+\t\tif (strstr(triple, \"powerpc64\") || strstr(triple, \"ppc64\"))\n+\t\t\ttrunc_len = 8;\n+\t\telse if (strstr(triple, \"powerpc\") || strstr(triple, \"ppc\"))\n+\t\t\ttrunc_len = 4;\n+\t\tLLVMDisposeMessage(triple);\n+\t}\n+\n \tfor (pc = 0, i = 0; i \u003c jited_funcs; ++i) {\n+\n \t\tfprintf(text_out, \"func #%d:\\n\", i);\n-\t\tdisasm_one_func(text_out, image + pc, func_lens[i]);\n+\t\t/*\n+\t\t * Disabled JIT have zero func_lens, hence underflow\n+\t\t */\n+\t\tdisasm_len = func_lens[i] \u003e trunc_len ?\n+\t\t\t\t\tfunc_lens[i] - trunc_len : 0;\n+\t\tdisasm_one_func(text_out, image + pc, disasm_len);\n+\n \t\tfprintf(text_out, \"\\n\");\n \t\tpc += func_lens[i];\n \t}\ndiff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h\nindex 9eeb5b0b63d697..cdc2a3de305405 100644\n--- a/tools/testing/selftests/bpf/progs/bpf_misc.h\n+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h\n@@ -158,6 +158,7 @@\n #define __arch_arm64\t\t__arch(\"ARM64\")\n #define __arch_riscv64\t\t__arch(\"RISCV64\")\n #define __arch_s390x\t\t__arch(\"s390x\")\n+#define __arch_powerpc64\t__arch(\"POWERPC64\")\n #define __caps_unpriv(caps)\t__test_tag(\"test_caps_unpriv=\" EXPAND_QUOTE(caps))\n #define __load_if_JITed()\t__test_tag(\"load_mode=jited\")\n #define __load_if_no_JITed()\t__test_tag(\"load_mode=no_jited\")\ndiff --git a/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c b/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c\nindex 48fa34d2959f46..09d7e92c849100 100644\n--- a/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c\n+++ b/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c\n@@ -91,6 +91,75 @@ __jited(\"\tpopq\t%rax\")\n __jited(\"\tjmp\t{{.*}}\")\t\t/* jump to tail call tgt   */\n __jited(\"L0:\tleave\")\n __jited(\"\t{{(retq|jmp\t0x)}}\")\t\t/* return or jump to rethunk */\n+__arch_powerpc64\n+/* program entry for main(), regular function prologue */\n+__jited(\"\tnop\")\n+__jited(\"...\")                          /* ld 2, 16(13) absent with CONFIG_PPC_KERNEL_PCREL */\n+__jited(\"\tli 9, 0\")\n+__jited(\"\tstd 9, -8(1)\")\n+__jited(\"\tmflr 0\")\n+__jited(\"\tstd 0, 16(1)\")\n+__jited(\"\tstdu 1, {{.*}}(1)\")\n+/* load address and call sub() via count register */\n+__jited(\"\tlis 12, {{.*}}\")\n+__jited(\"\tsldi 12, 12, 32\")\n+__jited(\"\toris 12, 12, {{.*}}\")\n+__jited(\"\tori 12, 12, {{.*}}\")\n+__jited(\"\tmtctr 12\")\n+__jited(\"\tbctrl\")\n+__jited(\"\tmr\t8, 3\")\n+__jited(\"\tli 8, 0\")\n+__jited(\"\taddi 1, 1, {{.*}}\")\n+__jited(\"\tld 0, 16(1)\")\n+__jited(\"\tmtlr 0\")\n+__jited(\"\tmr\t3, 8\")\n+__jited(\"\tblr\")\n+__jited(\"...\")\n+__jited(\"func #1\")\n+/* subprogram entry for sub() */\n+__jited(\"\tnop\")\n+__jited(\"...\")                          /* ld 2, 16(13) absent with CONFIG_PPC_KERNEL_PCREL */\n+/* tail call prologue for subprogram */\n+__jited(\"\tld 10, 0(1)\")\n+__jited(\"\tld 9, -8(10)\")\n+__jited(\"\tcmpldi\t9, 33\")\n+__jited(\"\tbt\t{{.*}}, {{.*}}\")\n+__jited(\"\taddi 9, 10, -8\")\n+__jited(\"\tstd 9, -8(1)\")\n+__jited(\"\tlis {{.*}}, {{.*}}\")\n+__jited(\"\tsldi {{.*}}, {{.*}}, 32\")\n+__jited(\"\toris {{.*}}, {{.*}}, {{.*}}\")\n+__jited(\"\tori {{.*}}, {{.*}}, {{.*}}\")\n+__jited(\"\tli {{.*}}, 0\")\n+__jited(\"\tlwz 9, {{.*}}({{.*}})\")\n+__jited(\"\tslwi {{.*}}, {{.*}}, 0\")\n+__jited(\"\tcmplw\t{{.*}}, 9\")\n+__jited(\"\tbf\t0, {{.*}}\")\n+/* bpf_tail_call implementation */\n+__jited(\"\tld 9, -8(1)\")\n+__jited(\"\tcmpldi\t9, 33\")\n+__jited(\"\tbf\t{{.*}}, {{.*}}\")\n+__jited(\"\tld 9, 0(9)\")\n+__jited(\"\tcmpldi\t9, 33\")\n+__jited(\"\tbt\t{{.*}}, {{.*}}\")\n+__jited(\"\taddi 9, 9, 1\")\n+__jited(\"\tmulli 10, {{.*}}, 8\")\n+__jited(\"\tadd 10, 10, {{.*}}\")\n+__jited(\"\tld 10, {{.*}}(10)\")\n+__jited(\"\tcmpldi\t10, 0\")\n+__jited(\"\tbt\t{{.*}}, {{.*}}\")\n+__jited(\"\tld 10, {{.*}}(10)\")\n+__jited(\"\taddi 10, 10, {{.*}}\")    /* offset depends on CONFIG_PPC_KERNEL_PCREL */\n+__jited(\"\tmtctr 10\")\n+__jited(\"\tld 10, -8(1)\")\n+__jited(\"\tcmpldi\t10, 33\")\n+__jited(\"\tbt\t{{.*}}, {{.*}}\")\n+__jited(\"\taddi 10, 1, -8\")\n+__jited(\"\tstd 9, 0(10)\")\n+__jited(\"\tbctr\")\n+__jited(\"\tmr\t3, 8\")\n+__jited(\"\tblr\")\n+\n SEC(\"tc\")\n __naked int main(void)\n {\ndiff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c\nindex abdb9e6e371362..d5589355ed9e0c 100644\n--- a/tools/testing/selftests/bpf/test_loader.c\n+++ b/tools/testing/selftests/bpf/test_loader.c\n@@ -377,6 +377,7 @@ enum arch {\n \tARCH_ARM64\t= 0x4,\n \tARCH_RISCV64\t= 0x8,\n \tARCH_S390X\t= 0x10,\n+\tARCH_POWERPC64\t= 0x20,\n };\n \n static int get_current_arch(void)\n@@ -389,6 +390,8 @@ static int get_current_arch(void)\n \treturn ARCH_RISCV64;\n #elif defined(__s390x__)\n \treturn ARCH_S390X;\n+#elif defined(__powerpc64__)\n+\treturn ARCH_POWERPC64;\n #endif\n \treturn ARCH_UNKNOWN;\n }\n@@ -580,6 +583,8 @@ static int parse_test_spec(struct test_loader *tester,\n \t\t\t\tarch = ARCH_RISCV64;\n \t\t\t} else if (strcmp(val, \"s390x\") == 0) {\n \t\t\t\tarch = ARCH_S390X;\n+\t\t\t} else if (strcmp(val, \"POWERPC64\") == 0) {\n+\t\t\t\tarch = ARCH_POWERPC64;\n \t\t\t} else {\n \t\t\t\tPRINT_FAIL(\"bad arch spec: '%s'\\n\", val);\n \t\t\t\terr = -EINVAL;\n"
}

2/1 2026/06/23 19:43 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "BPF_JIT",
    "FUNCTION_TRACER"
  ],
  "FocusSymbols": [
    "bpf_int_jit_compile",
    "bpf_jit_build_fentry_stubs",
    "bpf_jit_emit_exit_insn",
    "bpf_jit_build_epilogue",
    "bpf_jit_build_body",
    "bpf_jit_build_prologue",
    "bpf_jit_emit_tail_call",
    "bpf_trampoline_setup_tail_call_info",
    "bpf_arch_text_poke"
  ],
  "Reasoning": "The patch modifies the BPF JIT compiler for PowerPC, specifically adjusting the code generation passes, fentry stubs alignment, and epilogue/exit instructions. These changes affect how BPF programs are compiled and executed on PowerPC architectures. Fuzzing the BPF JIT compiler on PowerPC will help ensure the correctness of the generated machine code and prevent potential crashes or vulnerabilities.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit ee6a5643b9bb753aea7521ef52e8479d4f20777b
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Jun 23 19:43:20 2026 +0000

    syz-cluster: applied patch under review

diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index f32de8704d4d96..4da8bde92e1eff 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -14,6 +14,13 @@
 #include <asm/ppc-opcode.h>
 #include <linux/build_bug.h>
 
+/*
+ * We need at least 2 passes for proper code generation, and may need
+ * additional passes if code size changes between passes.
+ */
+#define CODEGEN_MIN_PASSES    2
+#define CODEGEN_MAX_PASSES    3
+
 #ifdef CONFIG_PPC64_ELF_ABI_V1
 #define FUNCTION_DESCR_SIZE	24
 #else
@@ -188,6 +195,12 @@ struct codegen_context {
 
 #define bpf_to_ppc(r)	(ctx->b2p[r])
 
+#ifdef CONFIG_PPC64
+#define PPC_RAW_CMPLLI(a, i)    PPC_RAW_CMPLDI(a, i)
+#else
+#define PPC_RAW_CMPLLI(a, i)    PPC_RAW_CMPLWI(a, i)
+#endif
+
 #ifdef CONFIG_PPC32
 #define BPF_FIXUP_LEN	3 /* Three instructions => 12 bytes */
 #else
@@ -214,10 +227,11 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *
 int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,
 		       u32 *addrs, int pass, bool extra_pass);
 void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
-void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx);
+void bpf_jit_build_epilogue(u32 *image, u32 *fimage, struct codegen_context *ctx);
+void bpf_jit_build_fentry_stubs(u32 *image, u32 *fimage, struct codegen_context *ctx);
 void bpf_jit_realloc_regs(struct codegen_context *ctx);
-int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr);
+int bpf_jit_emit_exit_insn(u32 *image, u32 *fimage, struct codegen_context *ctx, int tmp_reg,
+										long exit_addr);
 void prepare_for_fsession_fentry(u32 *image, struct codegen_context *ctx, int cookie_cnt,
 								int cookie_off, int retval_off);
 void store_func_meta(u32 *image, struct codegen_context *ctx, u64 func_meta, int func_meta_off);
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 6351a187ca61e2..46bbfb6be61340 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -49,11 +49,37 @@ asm (
 "	.popsection				;"
 );
 
-void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx)
+void bpf_jit_build_fentry_stubs(u32 *image, u32 *fimage, struct codegen_context *ctx)
 {
 	int ool_stub_idx, long_branch_stub_idx;
+	int stub_sz;
 
 	/*
+	 * The dummy_tramp_addr field is placed at bottom of Long branch stub.
+	 * In the final pass, align the mis-aligned dummy_tramp_addr field
+	 * in the fimage. The alignment NOP must appear before OOL stub,
+	 * to make ool_stub_idx & long_branch_stub_idx constant from end.
+	 *
+	 * dummy_tramp_addr must be 8-byte aligned for load-register
+	 * compatibility. The fimage can be non 8-byte aligned, so final
+	 * alignment depends on start of fimage and the stub's instruction
+	 * count. The stubs block has 11 instructions (with
+	 * CONFIG_PPC_FTRACE_OUT_OF_LINE) or 10 instructions (without)
+	 * before dummy_tramp_addr field. Emit a NOP if the address of
+	 * dummy_tramp_addr is non aligned.
+	 *
+	 * In pass=0 when image==NULL, conservatively account for space
+	 * required to accommodate alignment NOP. In case final pass skips
+	 * emitting alignment NOP, the image buffer have 4 spare bytes and
+	 * jited_len signifies correct program size.
+	 */
+
+	stub_sz = IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) ? 44 : 40;
+	if (!image || !IS_ALIGNED((unsigned long)fimage + ctx->idx*4 + stub_sz, SZL))
+		EMIT(PPC_RAW_NOP());
+
+	/*
+	 *      nop     // optional, for alignment of dummy_tramp_addr
 	 * Out-of-line stub:
 	 *	mflr	r0
 	 *	[b|bl]	tramp
@@ -70,44 +96,46 @@ void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx)
 
 	/*
 	 * Long branch stub:
-	 *	.long	<dummy_tramp_addr>
 	 *	mflr	r11
 	 *	bcl	20,31,$+4
-	 *	mflr	r12
-	 *	ld	r12, -8-SZL(r12)
+	 *	mflr	r12	// lr/r12 stores pc of current(this) inst.
+	 *	ld	r12, 20(r12) // offset(dummy_tramp_addr) from prev inst. is 20
 	 *	mtctr	r12
-	 *	mtlr	r11 // needed to retain ftrace ABI
+	 *	mtlr	r11	// needed to retain ftrace ABI
 	 *	bctr
+	 *	.long	<dummy_tramp_addr>  // 8-byte aligned
 	 */
-	if (image)
-		*((unsigned long *)&image[ctx->idx]) = (unsigned long)dummy_tramp;
-	ctx->idx += SZL / 4;
 	long_branch_stub_idx = ctx->idx;
 	EMIT(PPC_RAW_MFLR(_R11));
 	EMIT(PPC_RAW_BCL4());
 	EMIT(PPC_RAW_MFLR(_R12));
-	EMIT(PPC_RAW_LL(_R12, _R12, -8-SZL));
+	EMIT(PPC_RAW_LL(_R12, _R12, 20));
 	EMIT(PPC_RAW_MTCTR(_R12));
 	EMIT(PPC_RAW_MTLR(_R11));
 	EMIT(PPC_RAW_BCTR());
 
+	if (image)
+		*((unsigned long *)&image[ctx->idx]) = (unsigned long)dummy_tramp;
+
+	ctx->idx += SZL / 4;
+
 	if (!bpf_jit_ool_stub) {
 		bpf_jit_ool_stub = (ctx->idx - ool_stub_idx) * 4;
 		bpf_jit_long_branch_stub = (ctx->idx - long_branch_stub_idx) * 4;
 	}
 }
 
-int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr)
+int bpf_jit_emit_exit_insn(u32 *image, u32 *fimage, struct codegen_context *ctx,
+							int tmp_reg, long exit_addr)
 {
-	if (!exit_addr || is_offset_in_branch_range(exit_addr - (ctx->idx * 4))) {
+	if (exit_addr && is_offset_in_branch_range(exit_addr - (long)(ctx->idx * 4))) {
 		PPC_JMP(exit_addr);
-	} else if (ctx->alt_exit_addr) {
-		if (WARN_ON(!is_offset_in_branch_range((long)ctx->alt_exit_addr - (ctx->idx * 4))))
-			return -1;
+	} else if (ctx->alt_exit_addr && is_offset_in_branch_range(
+			(long)(ctx->alt_exit_addr) - (long)(ctx->idx * 4))) {
 		PPC_JMP(ctx->alt_exit_addr);
 	} else {
 		ctx->alt_exit_addr = ctx->idx * 4;
-		bpf_jit_build_epilogue(image, ctx);
+		bpf_jit_build_epilogue(image, fimage, ctx);
 	}
 
 	return 0;
@@ -274,6 +302,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
 	 */
 	if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
 		cgctx.idx = 0;
+		cgctx.alt_exit_addr = 0;
 		if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
 			goto out_err;
 	}
@@ -286,7 +315,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
 	 */
 	bpf_jit_build_prologue(NULL, &cgctx);
 	addrs[fp->len] = cgctx.idx * 4;
-	bpf_jit_build_epilogue(NULL, &cgctx);
+	bpf_jit_build_epilogue(NULL, NULL, &cgctx);
 
 	fixup_len = fp->aux->num_exentries * BPF_FIXUP_LEN * 4;
 	extable_len = fp->aux->num_exentries * sizeof(struct exception_table_entry);
@@ -306,8 +335,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
 	code_base = (u32 *)(image + FUNCTION_DESCR_SIZE);
 	fcode_base = (u32 *)(fimage + FUNCTION_DESCR_SIZE);
 
-	/* Code generation passes 1-2 */
-	for (pass = 1; pass < 3; pass++) {
+	/* Code generation passes 1-2+, loop until program size converges. */
+	for (pass = 1; pass <= CODEGEN_MAX_PASSES; pass++) {
+		u32 prev_proglen = proglen;
+
 		/* Now build the prologue, body code & epilogue for real. */
 		cgctx.idx = 0;
 		cgctx.alt_exit_addr = 0;
@@ -318,11 +349,26 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
 			bpf_jit_binary_pack_free(fhdr, hdr);
 			goto out_err;
 		}
-		bpf_jit_build_epilogue(code_base, &cgctx);
+		addrs[fp->len] = cgctx.idx * 4;
+		bpf_jit_build_epilogue(code_base, fcode_base, &cgctx);
+
+		proglen = cgctx.idx * 4;
 
 		if (bpf_jit_enable > 1)
 			pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass,
-				proglen - (cgctx.idx * 4), cgctx.seen);
+				prev_proglen - proglen, cgctx.seen);
+
+		/* Check if program size has converged, but ensure minimum passes */
+		if (pass >= CODEGEN_MIN_PASSES && proglen == prev_proglen)
+			break;
+
+		if (pass == CODEGEN_MAX_PASSES && proglen != prev_proglen) {
+			pr_err("BPF JIT: Program did not converge after %d passes\n",
+								CODEGEN_MAX_PASSES);
+			bpf_arch_text_copy(&fhdr->size, &hdr->size, sizeof(hdr->size));
+			bpf_jit_binary_pack_free(fhdr, hdr);
+			goto out_err;
+		}
 	}
 
 	if (bpf_jit_enable > 1)
@@ -357,7 +403,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
 				(void *)fimage + FUNCTION_DESCR_SIZE);
 
 out_addrs:
-		if (!image && priv_stack_ptr) {
+		if (!fp->jited && priv_stack_ptr) {
 			fp->aux->priv_stack_ptr = NULL;
 			free_percpu(priv_stack_ptr);
 		}
@@ -734,7 +780,7 @@ static void bpf_trampoline_setup_tail_call_info(u32 *image, struct codegen_conte
 		 * Setting the tail_call_info in trampoline's frame
 		 * depending on if previous frame had value or reference.
 		 */
-		EMIT(PPC_RAW_CMPLWI(_R3, MAX_TAIL_CALL_CNT));
+		EMIT(PPC_RAW_CMPLLI(_R3, MAX_TAIL_CALL_CNT));
 		PPC_BCC_CONST_SHORT(COND_GT, 8);
 		EMIT(PPC_RAW_ADDI(_R3, _R4, -BPF_PPC_TAILCALL));
 
@@ -1260,6 +1306,7 @@ static void do_isync(void *info __maybe_unused)
  * bpf_func:
  *	[nop|b]	ool_stub
  * 2. Out-of-line stub:
+ *	nop	// optional nop for alignment
  * ool_stub:
  *	mflr	r0
  *	[b|bl]	<bpf_prog>/<long_branch_stub>
@@ -1267,14 +1314,14 @@ static void do_isync(void *info __maybe_unused)
  *	b	bpf_func + 4
  * 3. Long branch stub:
  * long_branch_stub:
- *	.long	<branch_addr>/<dummy_tramp>
  *	mflr	r11
  *	bcl	20,31,$+4
  *	mflr	r12
- *	ld	r12, -16(r12)
+ *	ld	r12, 20(r12)
  *	mtctr	r12
  *	mtlr	r11 // needed to retain ftrace ABI
  *	bctr
+ *	.long	<branch_addr>/<dummy_tramp>
  *
  * dummy_tramp is used to reduce synchronization requirements.
  *
@@ -1376,10 +1423,12 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
 	 * 1. Update the address in the long branch stub:
 	 * If new_addr is out of range, we will have to use the long branch stub, so patch new_addr
 	 * here. Otherwise, revert to dummy_tramp, but only if we had patched old_addr here.
+	 *
+	 * dummy_tramp_addr moved to bottom of long branch stub.
 	 */
 	if ((new_addr && !is_offset_in_branch_range(new_addr - ip)) ||
 	    (old_addr && !is_offset_in_branch_range(old_addr - ip)))
-		ret = patch_ulong((void *)(bpf_func_end - bpf_jit_long_branch_stub - SZL),
+		ret = patch_ulong((void *)(bpf_func_end - SZL), /* SZL: dummy_tramp_addr offset */
 				  (new_addr && !is_offset_in_branch_range(new_addr - ip)) ?
 				  (unsigned long)new_addr : (unsigned long)dummy_tramp);
 	if (ret)
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index bfdc50740da8e7..f5b9441cf46aa7 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -229,7 +229,7 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx
 
 }
 
-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
+void bpf_jit_build_epilogue(u32 *image, u32 *fimage, struct codegen_context *ctx)
 {
 	EMIT(PPC_RAW_MR(_R3, bpf_to_ppc(BPF_REG_0)));
 
@@ -237,7 +237,7 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
 
 	EMIT(PPC_RAW_BLR());
 
-	bpf_jit_build_fentry_stubs(image, ctx);
+	bpf_jit_build_fentry_stubs(image, fimage, ctx);
 }
 
 /* Relative offset needs to be calculated based on final image location */
@@ -1149,7 +1149,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code
 			 * we'll just fall through to the epilogue.
 			 */
 			if (i != flen - 1) {
-				ret = bpf_jit_emit_exit_insn(image, ctx, _R0, exit_addr);
+				ret = bpf_jit_emit_exit_insn(image, fimage,
+								ctx, _R0, exit_addr);
 				if (ret)
 					return ret;
 			}
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index db364d9083e725..086084abb184a4 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -276,7 +276,7 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
 		 */
 		EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_2), _R1, 0));
 		EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_2), -(BPF_PPC_TAILCALL)));
-		EMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));
+		EMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));
 		PPC_BCC_CONST_SHORT(COND_GT, 8);
 		EMIT(PPC_RAW_ADDI(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_2),
 								-(BPF_PPC_TAILCALL)));
@@ -398,7 +398,7 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx
 	}
 }
 
-void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
+void bpf_jit_build_epilogue(u32 *image, u32 *fimage, struct codegen_context *ctx)
 {
 	bpf_jit_emit_common_epilogue(image, ctx);
 
@@ -407,7 +407,7 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
 
 	EMIT(PPC_RAW_BLR());
 
-	bpf_jit_build_fentry_stubs(image, ctx);
+	bpf_jit_build_fentry_stubs(image, fimage, ctx);
 }
 
 /*
@@ -651,7 +651,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
 	PPC_BCC_SHORT(COND_GE, out);
 
 	EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), _R1, bpf_jit_stack_tailcallinfo_offset(ctx)));
-	EMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));
+	EMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));
 	PPC_BCC_CONST_SHORT(COND_LE, 8);
 
 	/* dereference TMP_REG_1 */
@@ -661,7 +661,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
 	 * if (tail_call_info == MAX_TAIL_CALL_CNT)
 	 *   goto out;
 	 */
-	EMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));
+	EMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_1), MAX_TAIL_CALL_CNT));
 	PPC_BCC_SHORT(COND_EQ, out);
 
 	/*
@@ -696,7 +696,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
 	 * tail_call_info.
 	 */
 	EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_2), _R1, bpf_jit_stack_tailcallinfo_offset(ctx)));
-	EMIT(PPC_RAW_CMPLWI(bpf_to_ppc(TMP_REG_2), MAX_TAIL_CALL_CNT));
+	EMIT(PPC_RAW_CMPLDI(bpf_to_ppc(TMP_REG_2), MAX_TAIL_CALL_CNT));
 	PPC_BCC_CONST_SHORT(COND_GT, 8);
 
 	/* First get address of tail_call_info */
@@ -1726,7 +1726,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code
 			 * we'll just fall through to the epilogue.
 			 */
 			if (i != flen - 1) {
-				ret = bpf_jit_emit_exit_insn(image, ctx, tmp1_reg, exit_addr);
+				ret = bpf_jit_emit_exit_insn(image, fimage, ctx,
+								tmp1_reg, exit_addr);
 				if (ret)
 					return ret;
 			}
diff --git a/tools/testing/selftests/bpf/jit_disasm_helpers.c b/tools/testing/selftests/bpf/jit_disasm_helpers.c
index 3558fe10e28cf9..11428cad5b2d2b 100644
--- a/tools/testing/selftests/bpf/jit_disasm_helpers.c
+++ b/tools/testing/selftests/bpf/jit_disasm_helpers.c
@@ -178,10 +178,12 @@ int get_jited_program_text(int fd, char *text, size_t text_sz)
 {
 	struct bpf_prog_info info = {};
 	__u32 info_len = sizeof(info);
-	__u32 jited_funcs, len, pc;
+	__u32 jited_funcs, len, pc, disasm_len;
+	__u32 trunc_len = 0;
 	__u32 *func_lens = NULL;
 	FILE *text_out = NULL;
 	uint8_t *image = NULL;
+	char *triple = NULL;
 	int i, err = 0;
 
 	if (!llvm_initialized) {
@@ -225,9 +227,30 @@ int get_jited_program_text(int fd, char *text, size_t text_sz)
 	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd #2"))
 		goto out;
 
+	/*
+	 * last 8 bytes contains dummy_trampoline address in JIT
+	 * output on 64-bit and last 4 bytes on 32-bit powerpc,
+	 * which can't disassemble to a valid instruction.
+	 */
+	triple = LLVMGetDefaultTargetTriple();
+	if (triple) {
+		if (strstr(triple, "powerpc64") || strstr(triple, "ppc64"))
+			trunc_len = 8;
+		else if (strstr(triple, "powerpc") || strstr(triple, "ppc"))
+			trunc_len = 4;
+		LLVMDisposeMessage(triple);
+	}
+
 	for (pc = 0, i = 0; i < jited_funcs; ++i) {
+
 		fprintf(text_out, "func #%d:\n", i);
-		disasm_one_func(text_out, image + pc, func_lens[i]);
+		/*
+		 * Disabled JIT have zero func_lens, hence underflow
+		 */
+		disasm_len = func_lens[i] > trunc_len ?
+					func_lens[i] - trunc_len : 0;
+		disasm_one_func(text_out, image + pc, disasm_len);
+
 		fprintf(text_out, "\n");
 		pc += func_lens[i];
 	}
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 9eeb5b0b63d697..cdc2a3de305405 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -158,6 +158,7 @@
 #define __arch_arm64		__arch("ARM64")
 #define __arch_riscv64		__arch("RISCV64")
 #define __arch_s390x		__arch("s390x")
+#define __arch_powerpc64	__arch("POWERPC64")
 #define __caps_unpriv(caps)	__test_tag("test_caps_unpriv=" EXPAND_QUOTE(caps))
 #define __load_if_JITed()	__test_tag("load_mode=jited")
 #define __load_if_no_JITed()	__test_tag("load_mode=no_jited")
diff --git a/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c b/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c
index 48fa34d2959f46..09d7e92c849100 100644
--- a/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c
+++ b/tools/testing/selftests/bpf/progs/verifier_tailcall_jit.c
@@ -91,6 +91,75 @@ __jited("	popq	%rax")
 __jited("	jmp	{{.*}}")		/* jump to tail call tgt   */
 __jited("L0:	leave")
 __jited("	{{(retq|jmp	0x)}}")		/* return or jump to rethunk */
+__arch_powerpc64
+/* program entry for main(), regular function prologue */
+__jited("	nop")
+__jited("...")                          /* ld 2, 16(13) absent with CONFIG_PPC_KERNEL_PCREL */
+__jited("	li 9, 0")
+__jited("	std 9, -8(1)")
+__jited("	mflr 0")
+__jited("	std 0, 16(1)")
+__jited("	stdu 1, {{.*}}(1)")
+/* load address and call sub() via count register */
+__jited("	lis 12, {{.*}}")
+__jited("	sldi 12, 12, 32")
+__jited("	oris 12, 12, {{.*}}")
+__jited("	ori 12, 12, {{.*}}")
+__jited("	mtctr 12")
+__jited("	bctrl")
+__jited("	mr	8, 3")
+__jited("	li 8, 0")
+__jited("	addi 1, 1, {{.*}}")
+__jited("	ld 0, 16(1)")
+__jited("	mtlr 0")
+__jited("	mr	3, 8")
+__jited("	blr")
+__jited("...")
+__jited("func #1")
+/* subprogram entry for sub() */
+__jited("	nop")
+__jited("...")                          /* ld 2, 16(13) absent with CONFIG_PPC_KERNEL_PCREL */
+/* tail call prologue for subprogram */
+__jited("	ld 10, 0(1)")
+__jited("	ld 9, -8(10)")
+__jited("	cmpldi	9, 33")
+__jited("	bt	{{.*}}, {{.*}}")
+__jited("	addi 9, 10, -8")
+__jited("	std 9, -8(1)")
+__jited("	lis {{.*}}, {{.*}}")
+__jited("	sldi {{.*}}, {{.*}}, 32")
+__jited("	oris {{.*}}, {{.*}}, {{.*}}")
+__jited("	ori {{.*}}, {{.*}}, {{.*}}")
+__jited("	li {{.*}}, 0")
+__jited("	lwz 9, {{.*}}({{.*}})")
+__jited("	slwi {{.*}}, {{.*}}, 0")
+__jited("	cmplw	{{.*}}, 9")
+__jited("	bf	0, {{.*}}")
+/* bpf_tail_call implementation */
+__jited("	ld 9, -8(1)")
+__jited("	cmpldi	9, 33")
+__jited("	bf	{{.*}}, {{.*}}")
+__jited("	ld 9, 0(9)")
+__jited("	cmpldi	9, 33")
+__jited("	bt	{{.*}}, {{.*}}")
+__jited("	addi 9, 9, 1")
+__jited("	mulli 10, {{.*}}, 8")
+__jited("	add 10, 10, {{.*}}")
+__jited("	ld 10, {{.*}}(10)")
+__jited("	cmpldi	10, 0")
+__jited("	bt	{{.*}}, {{.*}}")
+__jited("	ld 10, {{.*}}(10)")
+__jited("	addi 10, 10, {{.*}}")    /* offset depends on CONFIG_PPC_KERNEL_PCREL */
+__jited("	mtctr 10")
+__jited("	ld 10, -8(1)")
+__jited("	cmpldi	10, 33")
+__jited("	bt	{{.*}}, {{.*}}")
+__jited("	addi 10, 1, -8")
+__jited("	std 9, 0(10)")
+__jited("	bctr")
+__jited("	mr	3, 8")
+__jited("	blr")
+
 SEC("tc")
 __naked int main(void)
 {
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index abdb9e6e371362..d5589355ed9e0c 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -377,6 +377,7 @@ enum arch {
 	ARCH_ARM64	= 0x4,
 	ARCH_RISCV64	= 0x8,
 	ARCH_S390X	= 0x10,
+	ARCH_POWERPC64	= 0x20,
 };
 
 static int get_current_arch(void)
@@ -389,6 +390,8 @@ static int get_current_arch(void)
 	return ARCH_RISCV64;
 #elif defined(__s390x__)
 	return ARCH_S390X;
+#elif defined(__powerpc64__)
+	return ARCH_POWERPC64;
 #endif
 	return ARCH_UNKNOWN;
 }
@@ -580,6 +583,8 @@ static int parse_test_spec(struct test_loader *tester,
 				arch = ARCH_RISCV64;
 			} else if (strcmp(val, "s390x") == 0) {
 				arch = ARCH_S390X;
+			} else if (strcmp(val, "POWERPC64") == 0) {
+				arch = ARCH_POWERPC64;
 			} else {
 				PRINT_FAIL("bad arch spec: '%s'\n", val);
 				err = -EINVAL;

3/2 2026/06/23 19:43 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10909
							output: 40
							thoughts: 942
						

Thoughts:
**Analyzing the PowerPC BPF JIT Compiler Patch**

Okay, so I'm looking at this patch that tweaks the BPF JIT compiler specifically for PowerPC. It looks like it's making some functional changes to the code generation passes (adjusting `CODEGEN_MIN_PASSES` and `CODEGEN_MAX_PASSES`). Beyond that, the patch appears to be modifying a series of core functions: `bpf_jit_build_fentry_stubs`, `bpf_jit_emit_exit_insn`, and `bpf_jit_build_epilogue`, along with some instruction replacements. The fact that it's touching these low-level code generation aspects suggests it could be impactful, and needs careful examination. Also, they've added PowerPC64 support to a couple of self-test files, which is good.

My initial thought is, is this reachable in the common environments? Since it's PowerPC, and I know syzkaller has support for PowerPC (specifically ppc64le), this is something worth testing, especially given syzkaller's fuzzing capabilities. I see that my first impression is correct, the patch is indeed fuzzable.

I need to focus on the code. Let me extract the key functions modified in `arch/powerpc/net/bpf_jit_comp.c`, `arch/powerpc/net/bpf_jit_comp32.c`, and `arch/powerpc/net/bpf_jit_comp64.c`. I have:
- `bpf_jit_build_fentry_stubs`
- `bpf_jit_emit_exit_insn`
- `bpf_int_jit_compile`
- `bpf_trampoline_setup_tail_call_info`
- `bpf_arch_text_poke`
- `bpf_jit_build_epilogue`
- `bpf_jit_emit_tail_call`
- `bpf_jit_build_body`
- `bpf_jit_build_prologue`

This is all core BPF JIT compiler stuff for PowerPC, so the impact is in the core. The configuration needed is simple, `BPF_JIT` and either `PPC64` or `PPC32`, but I think just saying `BPF_JIT` and `PPC64` covers it for fuzzing purposes. However, I should check for specific configurations that might be used by looking at the `#ifdef`s. Let me look at `arch/powerpc/net/bpf_jit_comp.c` to see if there are any conditional configurations, and I see `CONFIG_PPC_FTRACE_OUT_OF_LINE` being used in `bpf_jit_build_fentry_stubs`, so I'll keep that in mind.



4/2 2026/06/23 19:43 tool grepper
0m Args:
{
  "Expression": "CONFIG_PPC_FTRACE_OUT_OF_LINE",
  "PathPrefix": "arch/powerpc/net/"
}

Results:
{
  "Output": "arch/powerpc/net/bpf_jit_comp.c=35=asm (\n--\narch/powerpc/net/bpf_jit_comp.c-39-\"dummy_tramp:\t\t\t\t\t;\"\narch/powerpc/net/bpf_jit_comp.c:40:#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE\narch/powerpc/net/bpf_jit_comp.c-41-\"\tblr\t\t\t\t\t;\"\n--\narch/powerpc/net/bpf_jit_comp.c=52=void bpf_jit_build_fentry_stubs(u32 *image, u32 *fimage, struct codegen_context *ctx)\n--\narch/powerpc/net/bpf_jit_comp.c-66-\t * count. The stubs block has 11 instructions (with\narch/powerpc/net/bpf_jit_comp.c:67:\t * CONFIG_PPC_FTRACE_OUT_OF_LINE) or 10 instructions (without)\narch/powerpc/net/bpf_jit_comp.c-68-\t * before dummy_tramp_addr field. Emit a NOP if the address of\n--\narch/powerpc/net/bpf_jit_comp.c-76-\narch/powerpc/net/bpf_jit_comp.c:77:\tstub_sz = IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) ? 44 : 40;\narch/powerpc/net/bpf_jit_comp.c-78-\tif (!image || !IS_ALIGNED((unsigned long)fimage + ctx-\u003eidx*4 + stub_sz, SZL))\n--\narch/powerpc/net/bpf_jit_comp.c-85-\t *\t[b|bl]\ttramp\narch/powerpc/net/bpf_jit_comp.c:86:\t *\tmtlr\tr0 // only with CONFIG_PPC_FTRACE_OUT_OF_LINE\narch/powerpc/net/bpf_jit_comp.c-87-\t *\tb\tbpf_func + 4\n--\narch/powerpc/net/bpf_jit_comp.c-91-\tEMIT(PPC_RAW_NOP());\narch/powerpc/net/bpf_jit_comp.c:92:\tif (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE))\narch/powerpc/net/bpf_jit_comp.c-93-\t\tEMIT(PPC_RAW_MTLR(_R0));\n--\narch/powerpc/net/bpf_jit_comp.c=853=static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_image,\n--\narch/powerpc/net/bpf_jit_comp.c-972-\t/* Optional save area for actual LR in case of ool ftrace */\narch/powerpc/net/bpf_jit_comp.c:973:\tif (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) {\narch/powerpc/net/bpf_jit_comp.c-974-\t\talt_lr_off = bpf_frame_size;\n--\narch/powerpc/net/bpf_jit_comp.c-1017-\tEMIT(PPC_RAW_MFLR(_R3));\narch/powerpc/net/bpf_jit_comp.c:1018:\tif (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE))\narch/powerpc/net/bpf_jit_comp.c-1019-\t\tEMIT(PPC_RAW_STL(_R3, _R1, alt_lr_off));\n--\narch/powerpc/net/bpf_jit_comp.c-1024-\t * Derive IP address of the traced function.\narch/powerpc/net/bpf_jit_comp.c:1025:\t * In case of CONFIG_PPC_FTRACE_OUT_OF_LINE or BPF program, LR points to the instruction\narch/powerpc/net/bpf_jit_comp.c-1026-\t * after the 'bl' instruction in the OOL stub. Refer to ftrace_init_ool_stub() and\n--\narch/powerpc/net/bpf_jit_comp.c-1036-\t */\narch/powerpc/net/bpf_jit_comp.c:1037:\tif (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) || flags \u0026 BPF_TRAMP_F_IP_ARG) {\narch/powerpc/net/bpf_jit_comp.c-1038-\t\tEMIT(PPC_RAW_LWZ(_R4, _R3, 4));\n--\narch/powerpc/net/bpf_jit_comp.c-1046-\narch/powerpc/net/bpf_jit_comp.c:1047:\tif (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) {\narch/powerpc/net/bpf_jit_comp.c-1048-\t\t/* Fake our LR for BPF_TRAMP_F_CALL_ORIG case */\n--\narch/powerpc/net/bpf_jit_comp.c-1204-\t} else {\narch/powerpc/net/bpf_jit_comp.c:1205:\t\tif (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) {\narch/powerpc/net/bpf_jit_comp.c-1206-\t\t\tEMIT(PPC_RAW_LL(_R0, _R1, alt_lr_off));\n--\narch/powerpc/net/bpf_jit_comp.c=1298=static void do_isync(void *info __maybe_unused)\n--\narch/powerpc/net/bpf_jit_comp.c-1312- *\t[b|bl]\t\u003cbpf_prog\u003e/\u003clong_branch_stub\u003e\narch/powerpc/net/bpf_jit_comp.c:1313: *\tmtlr\tr0 // CONFIG_PPC_FTRACE_OUT_OF_LINE only\narch/powerpc/net/bpf_jit_comp.c-1314- *\tb\tbpf_func + 4\n"
}

5/2 2026/06/23 19:43 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14110
							output: 36
							thoughts: 111
						

Thoughts:
**Analyzing the BPF JIT Patch for PowerPC**

Okay, so this patch is digging into the BPF JIT implementation for PowerPC. Specifically, it seems to be focused on the `fentry` stubs, the epilogue, and the exit instructions. Interesting. I'll need to look closely at how these are being modified, especially within that JIT context. It's also making adjustments to the number of passes the code generation goes through, which likely impacts performance or code quality.

The key configs at play here are clearly `BPF_JIT` and the architecture-specific `PPC64` or `PPC32`. Obvious. But there's also `CONFIG_PPC_FTRACE_OUT_OF_LINE` mentioned. I need to quickly verify that this config actually *exists* and is valid in the context of the PowerPC kernel configuration. Its relevance here suggests a relationship with function tracing and how it interacts with the JIT'd BPF code, which warrants further investigation. Let me check that config definition.



6/2 2026/06/23 19:43 tool grepper
0m Args:
{
  "Expression": "config PPC_FTRACE_OUT_OF_LINE",
  "PathPrefix": "arch/powerpc/"
}

Results:
{
  "Output": "arch/powerpc/Kconfig=568=config ARCH_USING_PATCHABLE_FUNCTION_ENTRY\n--\narch/powerpc/Kconfig-574-\narch/powerpc/Kconfig:575:config PPC_FTRACE_OUT_OF_LINE\narch/powerpc/Kconfig-576-\tdef_bool PPC64 \u0026\u0026 ARCH_USING_PATCHABLE_FUNCTION_ENTRY\n--\narch/powerpc/Kconfig-578-\narch/powerpc/Kconfig:579:config PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE\narch/powerpc/Kconfig-580-\tint \"Number of ftrace out-of-line stubs to reserve within .text\"\n"
}

7/2 2026/06/23 19:43 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14665
							output: 36
							thoughts: 88
						

Thoughts:
Okay, here's my take on those thoughts, framed from my expert perspective:

**Evaluating the `PPC_FTRACE_OUT_OF_LINE` Configuration Option**

Alright, so `PPC_FTRACE_OUT_OF_LINE` is a `def_bool`, which means it's not a direct option you can *select*. Its value is *defined* by something else: specifically, the conjunction of `PPC64` *and* `ARCH_USING_PATCHABLE_FUNCTION_ENTRY`. So, it's a sort of 'helper' or derived option. You can't toggle this one on or off directly in your config.

The more interesting bit here is `ARCH_USING_PATCHABLE_FUNCTION_ENTRY`. That's where the real control lies. If that flag is set, and we're on a PPC64 architecture, *then* `PPC_FTRACE_OUT_OF_LINE` is automatically enabled. It's a dependency. We need to figure out what controls the `ARCH_USING_PATCHABLE_FUNCTION_ENTRY` option so we can know if ftrace support is enabled.



8/2 2026/06/23 19:43 tool grepper
0m Args:
{
  "Expression": "config ARCH_USING_PATCHABLE_FUNCTION_ENTRY",
  "PathPrefix": "arch/powerpc/"
}

Results:
{
  "Output": "arch/powerpc/Kconfig=563=config MPROFILE_KERNEL\n--\narch/powerpc/Kconfig-567-\narch/powerpc/Kconfig:568:config ARCH_USING_PATCHABLE_FUNCTION_ENTRY\narch/powerpc/Kconfig-569-\tdepends on FUNCTION_TRACER \u0026\u0026 (PPC32 || PPC64_ELF_ABI_V2)\n"
}

9/2 2026/06/23 19:43 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15142
							output: 38
							thoughts: 724
						

Thoughts:
**My Configuration Assessment**

Okay, so I need to figure out the right kernel configurations for this code modification. First, `FUNCTION_TRACER` seems like a given, let's start with that. Now, I see `BPF_JIT` is definitely needed, which makes sense since it's the BPF JIT compiler. Naturally, `BPF_JIT` requires `BPF_SYSCALL` as well. So, the base requirements are `BPF_JIT` and `FUNCTION_TRACER`.

The prompt is specific: I should avoid listing too generic configs. Okay, `BPF_JIT` *is* specific to the JIT aspect, even if BPF is more general. `PPC_FTRACE_OUT_OF_LINE` is specific but not directly selectable. Now, let me check the functions involved to narrow this down. I see calls to `bpf_jit_build_fentry_stubs`, which in turn, is called from `bpf_jit_build_epilogue`. Also, `bpf_jit_emit_exit_insn` is called from `bpf_jit_build_body`.

Let's grab a list of `FocusSymbols`: `bpf_jit_build_fentry_stubs`, `bpf_jit_emit_exit_insn`, `bpf_int_jit_compile`, `bpf_jit_build_epilogue`, `bpf_jit_build_body`, `bpf_jit_build_prologue`, `bpf_jit_emit_tail_call`, `bpf_trampoline_setup_tail_call_info`, and `bpf_arch_text_poke`.

I need to confirm these symbols are not in the hot path. `bpf_int_jit_compile` is used during BPF program load and compilation. Good, not hot path. The `bpf_jit_*` functions are all part of the JIT compilation process; that makes sense. `bpf_trampoline_setup_tail_call_info` is for trampoline setup. `bpf_arch_text_poke` is used for patching BPF programs. Everything checks out.

Now, any other specific configs? Looks like `CONFIG_PPC64` and `CONFIG_PPC32` are used, along with `CONFIG_PPC_FTRACE_OUT_OF_LINE`. Okay, wait. These are architectures, not something I can enable on x86 directly. The configs I provide will be added to the kernel config.

So, in summary, based on the provided code, I can confidently list `BPF_JIT` and `FUNCTION_TRACER`. Let me double-check `bpf_jit_emit_exit_insn` is indeed in the expected file and architecture.



10/2 2026/06/23 19:43 tool grepper
0m Args:
{
  "Expression": "bpf_jit_emit_exit_insn",
  "PathPrefix": "arch/powerpc/net/"
}

Results:
{
  "Output": "arch/powerpc/net/bpf_jit.h=232=void bpf_jit_realloc_regs(struct codegen_context *ctx);\narch/powerpc/net/bpf_jit.h:233:int bpf_jit_emit_exit_insn(u32 *image, u32 *fimage, struct codegen_context *ctx, int tmp_reg,\narch/powerpc/net/bpf_jit.h-234-\t\t\t\t\t\t\t\t\t\tlong exit_addr);\n--\narch/powerpc/net/bpf_jit_comp.c=52=void bpf_jit_build_fentry_stubs(u32 *image, u32 *fimage, struct codegen_context *ctx)\n--\narch/powerpc/net/bpf_jit_comp.c-127-\narch/powerpc/net/bpf_jit_comp.c:128:int bpf_jit_emit_exit_insn(u32 *image, u32 *fimage, struct codegen_context *ctx,\narch/powerpc/net/bpf_jit_comp.c-129-\t\t\t\t\t\t\tint tmp_reg, long exit_addr)\n--\narch/powerpc/net/bpf_jit_comp32.c=322=int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,\n--\narch/powerpc/net/bpf_jit_comp32.c-1151-\t\t\tif (i != flen - 1) {\narch/powerpc/net/bpf_jit_comp32.c:1152:\t\t\t\tret = bpf_jit_emit_exit_insn(image, fimage,\narch/powerpc/net/bpf_jit_comp32.c-1153-\t\t\t\t\t\t\t\tctx, _R0, exit_addr);\n--\narch/powerpc/net/bpf_jit_comp64.c=956=int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,\n--\narch/powerpc/net/bpf_jit_comp64.c-1728-\t\t\tif (i != flen - 1) {\narch/powerpc/net/bpf_jit_comp64.c:1729:\t\t\t\tret = bpf_jit_emit_exit_insn(image, fimage, ctx,\narch/powerpc/net/bpf_jit_comp64.c-1730-\t\t\t\t\t\t\t\ttmp1_reg, exit_addr);\n"
}

11/2 2026/06/23 19:43 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 17182
							output: 239
							thoughts: 423
						

Thoughts:
**Analyzing the PowerPC BPF JIT Compiler Patch**

Okay, so I've got this patch here, and it's pretty clear that it's digging into the BPF JIT compiler specifically for PowerPC. It's not just a superficial tweak; these are functional changes affecting how the code is generated. We're talking about addressing alignment issues and modifying the code generation passes themselves – the very core of how BPF programs translate into PowerPC machine code. I can see that this is something that's reachable and used when BPF programs are loaded on PowerPC.

My immediate thought is, this is definitely something we need to fuzz. Given the scope of these changes, the potential for introducing subtle bugs or even vulnerabilities in the generated machine code is significant. We need to validate that the changes correctly handle various BPF program structures and inputs and prevent any unexpected behavior or crashes.

I've identified the key functions to focus my efforts on. We have `bpf_int_jit_compile` which is the central compile function. Then there is `bpf_jit_build_fentry_stubs`, `bpf_jit_emit_exit_insn`, `bpf_jit_build_epilogue`, `bpf_jit_build_body`, and `bpf_jit_build_prologue`. These seem to be the building blocks involved in constructing and finalizing the JIT'd code. Finally, there's `bpf_jit_emit_tail_call`, `bpf_trampoline_setup_tail_call_info`, and `bpf_arch_text_poke`. It's going to be essential to target these functions during fuzzing.

I'm confident that fuzzing these functions with `BPF_JIT` and `FUNCTION_TRACER` enabled will be crucial to ensure the overall stability and correctness of BPF on PowerPC. Alright, I'll go ahead and set the results now.



12/2 2026/06/23 19:44 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BPF_JIT",
    "FUNCTION_TRACER"
  ],
  "FocusSymbols": [
    "bpf_int_jit_compile",
    "bpf_jit_build_fentry_stubs",
    "bpf_jit_emit_exit_insn",
    "bpf_jit_build_epilogue",
    "bpf_jit_build_body",
    "bpf_jit_build_prologue",
    "bpf_jit_emit_tail_call",
    "bpf_trampoline_setup_tail_call_info",
    "bpf_arch_text_poke"
  ],
  "Reasoning": "The patch modifies the BPF JIT compiler for PowerPC, specifically adjusting the code generation passes, fentry stubs alignment, and epilogue/exit instructions. These changes affect how BPF programs are compiled and executed on PowerPC architectures. Fuzzing the BPF JIT compiler on PowerPC will help ensure the correctness of the generated machine code and prevent potential crashes or vulnerabilities.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BPF_JIT",
    "FUNCTION_TRACER"
  ],
  "FocusSymbols": [
    "bpf_int_jit_compile",
    "bpf_jit_build_fentry_stubs",
    "bpf_jit_emit_exit_insn",
    "bpf_jit_build_epilogue",
    "bpf_jit_build_body",
    "bpf_jit_build_prologue",
    "bpf_jit_emit_tail_call",
    "bpf_trampoline_setup_tail_call_info",
    "bpf_arch_text_poke"
  ],
  "Reasoning": "The patch modifies the BPF JIT compiler for PowerPC, specifically adjusting the code generation passes, fentry stubs alignment, and epilogue/exit instructions. These changes affect how BPF programs are compiled and executed on PowerPC architectures. Fuzzing the BPF JIT compiler on PowerPC will help ensure the correctness of the generated machine code and prevent potential crashes or vulnerabilities.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)