diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 6ede84ff987835..02e3b7e4807680 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -32,6 +32,8 @@ config ARC select HAVE_ARCH_TRANSPARENT_HUGEPAGE if ARC_MMU_V4 select HAVE_DEBUG_STACKOVERFLOW select HAVE_DEBUG_KMEMLEAK + select HAVE_FUNCTION_TRACER if (ISA_ARCV2 || ISA_ARCV3) + select HAVE_FUNCTION_GRAPH_TRACER if ISA_ARCV3 || (ISA_ARCV2 && GCC_VERSION >= 140000) select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_IOREMAP_PROT if !(ISA_ARCV3 && !64BIT) select HAVE_KERNEL_GZIP diff --git a/arch/arc/Makefile b/arch/arc/Makefile index 03dd4ba4dc2b6f..1a809ff65e6d22 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -19,6 +19,12 @@ endif endif endif +ifdef CONFIG_FTRACE +ifdef CONFIG_ISA_ARCV3 +cflags-y += -fno-omit-frame-pointer +endif +endif + ifdef CONFIG_ISA_ARCV3 ifdef CONFIG_64BIT UTS_MACHINE := arc64 diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index c16243d8749586..6c097d25cf9586 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -7,6 +7,16 @@ obj-y := arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o obj-y += ctx_sw_asm.o +ifdef CONFIG_FTRACE +# ftrace can't be traced (infinite loop) +CFLAGS_REMOVE_ftrace.o = -pg +CFLAGS_REMOVE_mcount.o = -pg + +obj-$(CONFIG_FUNCTION_TRACER) += mcount.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o + +endif + ifdef CONFIG_ISA_ARCOMPACT obj-y += intc-compact.o else diff --git a/arch/arc/kernel/ftrace.c b/arch/arc/kernel/ftrace.c new file mode 100644 index 00000000000000..c93a1fbcb04b06 --- /dev/null +++ b/arch/arc/kernel/ftrace.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Function tracing support for ARC + * + * Copyright (C) 2023 Synopsys, Inc. (www.synopsys.com) + */ + +#include + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +/* + * Setup return hook in traced routine + * Function copied from riscv + */ +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + unsigned long frame_pointer) +{ + unsigned long return_hooker = (unsigned long)&return_to_handler; + unsigned long old; + + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; + + old = *parent; + + if (!function_graph_enter(old, self_addr, frame_pointer, parent)) + *parent = return_hooker; +} + +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/arc/kernel/mcount.S b/arch/arc/kernel/mcount.S new file mode 100644 index 00000000000000..20ab11b0dacdc4 --- /dev/null +++ b/arch/arc/kernel/mcount.S @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Function tracing support for ARC + * + * Copyright (C) 2023 Synopsys, Inc. (www.synopsys.com) + */ + +#include +#include +#include + +; ftrace placeholder, just return to caller +ENTRY(ftrace_stub) + j_s [blink] +ENDPROC(ftrace_stub) + +.macro SAVE_ABI + PUSHR blink + PUSHR fp +.endm + +.macro LOAD_ABI + POPR fp + POPR blink +.endm + +.macro SAVE_ABI_RET + PUSHR r0 + PUSHR r1 +.endm + +.macro LOAD_ABI_RET + POPR r1 + POPR r0 +.endm + +; r0 has the frompc (targets parent ip) +; blink has the selfpc (target ip) +ENTRY(_mcount) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + + ; *ftrace_graph_return != ftrace_stub + MOVA r3, ftrace_graph_return + LDR r3, r3 + MOVA r4, @ftrace_stub + brne r3, r4, @do_ftrace_graph_caller + ; *ftrace_graph_entry != *ftrace_graph_entry_stub + MOVA r3, @ftrace_graph_entry + LDR r3, r3 + MOVA r4, @ftrace_graph_entry_stub + brne r3, r4, @do_ftrace_graph_caller + +#endif + + ; *ftrace_trace_function != ftrace_stub + MOVA r2, ftrace_trace_function + LDR r2, r2 + MOVA r3, @ftrace_stub + brne r2, r3, @do_trace + ; Return + j_s [blink] + +ENDPROC(_mcount) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +; Return to the actual caller +ENTRY(return_to_handler) + ; Save return value (if any) from handled routine + SAVE_ABI_RET + ; Will return true blink on r0 + MOVA r0, @ftrace_return_to_handler + jl [r0] + MOVR r2, r0 + LOAD_ABI_RET + j [r2] + +ENDPROC(return_to_handler) + +do_ftrace_graph_caller: + +#ifndef CONFIG_ISA_ARCV3 + ; ABI does not allow us to infer blink location + ; ARC GCC port inserts into r1 the delta between the pushed blink and + ; the sp at call time + ; We perform calculation before any push (sp change) happens + ADDR r0, r1, sp + SAVE_ABI + SUBR r0, r0, REGSZASM +#else + SAVE_ABI + ADDR r0, fp, REGSZASM +#endif + + MOVR r1, blink + MOVA r2, @prepare_ftrace_return + jl [r2] + LOAD_ABI + j_s [blink] +#endif + +do_trace: + SAVE_ABI + MOVR r1, r0 + MOVR r0, blink + jl [r2] + ; load ABI state and jump to blink (in stack) + LOAD_ABI + j_s [blink] + +EXPORT_SYMBOL(_mcount)