Commit db54c287 authored by Hari Bathini's avatar Hari Bathini Committed by Madhavan Srinivasan
Browse files

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: default avatarHari Bathini <hbathini@linux.ibm.com>
Tested-by: default avatarVenkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: default avatarMadhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20260127084926.34497-4-hbathini@linux.ibm.com
parent 875612a7
Loading
Loading
Loading
Loading
+22 −4
Original line number Diff line number Diff line
@@ -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)) {
	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;