From: Hari Bathini Date: Tue, 27 Jan 2026 08:49:26 +0000 (+0530) Subject: powerpc64/ftrace: workaround clang recording GEP in __patchable_function_entries X-Git-Tag: v7.0-rc4~40^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db54c28702f7270e74dce36c84cb0db4cec96389;p=thirdparty%2Flinux.git powerpc64/ftrace: workaround clang recording GEP in __patchable_function_entries Support for -fpatchable-function-entry on ppc64le was added in Clang with [1]. However, when no prefix NOPs are specified - as is the case with CONFIG_PPC_FTRACE_OUT_OF_LINE - the first NOP is emitted at LEP, but Clang records the Global Entry Point (GEP) unlike GCC which does record the Local Entry Point (LEP). Issue [2] has been raised to align Clang's behavior with GCC. As a temporary workaround to ensure ftrace initialization works as expected with Clang, derive the LEP using ppc_function_entry() for kernel symbols and by looking for the below module GEP sequence for module addresses, until [2] is resolved: ld r2, -8(r12) add r2, r2, r12 [1] https://github.com/llvm/llvm-project/pull/151569 [2] https://github.com/llvm/llvm-project/issues/163706 Signed-off-by: Hari Bathini Tested-by: Venkat Rao Bagalkote Signed-off-by: Madhavan Srinivasan Link: https://patch.msgid.link/20260127084926.34497-4-hbathini@linux.ibm.com --- diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c index 841d077e2825..1b2f293e7dcb 100644 --- a/arch/powerpc/kernel/trace/ftrace.c +++ b/arch/powerpc/kernel/trace/ftrace.c @@ -37,11 +37,29 @@ unsigned long ftrace_call_adjust(unsigned long addr) if (addr >= (unsigned long)__exittext_begin && addr < (unsigned long)__exittext_end) return 0; - if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY) && - !IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) { - addr += MCOUNT_INSN_SIZE; - if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) { + if (!IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) { addr += MCOUNT_INSN_SIZE; + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + addr += MCOUNT_INSN_SIZE; + } else if (IS_ENABLED(CONFIG_CC_IS_CLANG) && IS_ENABLED(CONFIG_PPC64)) { + /* + * addr points to global entry point though the NOP was emitted at local + * entry point due to https://github.com/llvm/llvm-project/issues/163706 + * Handle that here with ppc_function_entry() for kernel symbols while + * adjusting module addresses in the else case, by looking for the below + * module global entry point sequence: + * ld r2, -8(r12) + * add r2, r2, r12 + */ + if (is_kernel_text(addr) || is_kernel_inittext(addr)) + addr = ppc_function_entry((void *)addr); + else if ((ppc_inst_val(ppc_inst_read((u32 *)addr)) == + PPC_RAW_LD(_R2, _R12, -8)) && + (ppc_inst_val(ppc_inst_read((u32 *)(addr+4))) == + PPC_RAW_ADD(_R2, _R2, _R12))) + addr += 8; + } } return addr;