riscv: ftrace: Make function graph use ftrace directly
authorSong Shuai <suagrfillet@gmail.com>
Thu, 30 Nov 2023 12:15:29 +0000 (13:15 +0100)
committerPalmer Dabbelt <palmer@rivosinc.com>
Thu, 18 Jan 2024 02:17:08 +0000 (18:17 -0800)
Similar to commit 0c0593b45c9b ("x86/ftrace: Make function graph use
ftrace directly") and commit c4a0ebf87ceb ("arm64/ftrace: Make
function graph use ftrace directly"), RISC-V has no need for a special
graph tracer hook. The graph_ops::func function can be used to install
the return_hooker.

This cleanup only changes the FTRACE_WITH_REGS implementation, leaving
the mcount-based implementation is unaffected.

Perform the simplification, and also cleanup the register save/restore
macros.

Signed-off-by: Song Shuai <suagrfillet@gmail.com>
Tested-by: Guo Ren <guoren@kernel.org>
Signed-off-by: Guo Ren <guoren@kernel.org>
Acked-by: Björn Töpel <bjorn@rivosinc.com>
Link: https://lore.kernel.org/r/20231130121531.1178502-3-bjorn@kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/include/asm/ftrace.h
arch/riscv/kernel/ftrace.c
arch/riscv/kernel/mcount-dyn.S

index 2b2f5df7ef2c7de42216b4166ae3d1f4a789731f..b383926f73be1c08dc29bec204c2ba9d698c65e2 100644 (file)
@@ -128,7 +128,16 @@ do {                                                                       \
 struct dyn_ftrace;
 int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
 #define ftrace_init_nop ftrace_init_nop
-#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+struct ftrace_ops;
+struct ftrace_regs;
+void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+                      struct ftrace_ops *op, struct ftrace_regs *fregs);
+#define ftrace_graph_func ftrace_graph_func
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
index 03a6434a8cdd0035bbc59629b1751c00df24b918..f5aa24d9e1c150e651f5eeb144da8671e9ac5ddc 100644 (file)
@@ -178,32 +178,28 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
 }
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+                      struct ftrace_ops *op, struct ftrace_regs *fregs)
+{
+       struct pt_regs *regs = arch_ftrace_get_regs(fregs);
+       unsigned long *parent = (unsigned long *)&regs->ra;
+
+       prepare_ftrace_return(parent, ip, frame_pointer(regs));
+}
+#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
 extern void ftrace_graph_call(void);
-extern void ftrace_graph_regs_call(void);
 int ftrace_enable_ftrace_graph_caller(void)
 {
-       int ret;
-
-       ret = __ftrace_modify_call((unsigned long)&ftrace_graph_call,
-                                   (unsigned long)&prepare_ftrace_return, true, true);
-       if (ret)
-               return ret;
-
-       return __ftrace_modify_call((unsigned long)&ftrace_graph_regs_call,
+       return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
                                    (unsigned long)&prepare_ftrace_return, true, true);
 }
 
 int ftrace_disable_ftrace_graph_caller(void)
 {
-       int ret;
-
-       ret = __ftrace_modify_call((unsigned long)&ftrace_graph_call,
-                                   (unsigned long)&prepare_ftrace_return, false, true);
-       if (ret)
-               return ret;
-
-       return __ftrace_modify_call((unsigned long)&ftrace_graph_regs_call,
+       return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
                                    (unsigned long)&prepare_ftrace_return, false, true);
 }
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
 #endif /* CONFIG_DYNAMIC_FTRACE */
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
index 58dd96a2a15340ee83c473436a1b2cf25d407c1f..c902a7ddb3106c250285ac01af5a6b8c96062751 100644 (file)
        .endm
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
-       .macro SAVE_ALL
+
+/**
+* SAVE_ABI_REGS - save regs against the pt_regs struct
+*
+* @all: tell if saving all the regs
+*
+* If all is set, all the regs will be saved, otherwise only ABI
+* related regs (a0-a7,epc,ra and optional s0) will be saved.
+*
+* After the stack is established,
+*
+* 0(sp) stores the PC of the traced function which can be accessed
+* by &(fregs)->regs->epc in tracing function. Note that the real
+* function entry address should be computed with -FENTRY_RA_OFFSET.
+*
+* 8(sp) stores the function return address (i.e. parent IP) that
+* can be accessed by &(fregs)->regs->ra in tracing function.
+*
+* The other regs are saved at the respective localtion and accessed
+* by the respective pt_regs member.
+*
+* Here is the layout of stack for your reference.
+*
+* PT_SIZE_ON_STACK  ->  +++++++++
+*                       + ..... +
+*                       + t3-t6 +
+*                       + s2-s11+
+*                       + a0-a7 + --++++-> ftrace_caller saved
+*                       + s1    +   +
+*                       + s0    + --+
+*                       + t0-t2 +   +
+*                       + tp    +   +
+*                       + gp    +   +
+*                       + sp    +   +
+*                       + ra    + --+ // parent IP
+*               sp  ->  + epc   + --+ // PC
+*                       +++++++++
+**/
+       .macro SAVE_ABI_REGS, all=0
        addi    sp, sp, -PT_SIZE_ON_STACK
 
-       REG_S t0,  PT_EPC(sp)
-       REG_S x1,  PT_RA(sp)
-       REG_S x2,  PT_SP(sp)
-       REG_S x3,  PT_GP(sp)
-       REG_S x4,  PT_TP(sp)
-       REG_S x5,  PT_T0(sp)
-       save_from_x6_to_x31
+       REG_S   t0,  PT_EPC(sp)
+       REG_S   x1,  PT_RA(sp)
+
+       // save the ABI regs
+
+       REG_S   x10, PT_A0(sp)
+       REG_S   x11, PT_A1(sp)
+       REG_S   x12, PT_A2(sp)
+       REG_S   x13, PT_A3(sp)
+       REG_S   x14, PT_A4(sp)
+       REG_S   x15, PT_A5(sp)
+       REG_S   x16, PT_A6(sp)
+       REG_S   x17, PT_A7(sp)
+
+       // save the leftover regs
+
+       .if \all == 1
+       REG_S   x2, PT_SP(sp)
+       REG_S   x3, PT_GP(sp)
+       REG_S   x4, PT_TP(sp)
+       REG_S   x5, PT_T0(sp)
+       REG_S   x6, PT_T1(sp)
+       REG_S   x7, PT_T2(sp)
+       REG_S   x8, PT_S0(sp)
+       REG_S   x9, PT_S1(sp)
+       REG_S   x18, PT_S2(sp)
+       REG_S   x19, PT_S3(sp)
+       REG_S   x20, PT_S4(sp)
+       REG_S   x21, PT_S5(sp)
+       REG_S   x22, PT_S6(sp)
+       REG_S   x23, PT_S7(sp)
+       REG_S   x24, PT_S8(sp)
+       REG_S   x25, PT_S9(sp)
+       REG_S   x26, PT_S10(sp)
+       REG_S   x27, PT_S11(sp)
+       REG_S   x28, PT_T3(sp)
+       REG_S   x29, PT_T4(sp)
+       REG_S   x30, PT_T5(sp)
+       REG_S   x31, PT_T6(sp)
+
+       // save s0 if FP_TEST defined
+
+       .else
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+       REG_S   x8, PT_S0(sp)
+#endif
+       .endif
        .endm
 
-       .macro RESTORE_ALL
-       REG_L x1,  PT_RA(sp)
-       REG_L x2,  PT_SP(sp)
-       REG_L x3,  PT_GP(sp)
-       REG_L x4,  PT_TP(sp)
-       /* Restore t0 with PT_EPC */
-       REG_L x5,  PT_EPC(sp)
-       restore_from_x6_to_x31
-
+       .macro RESTORE_ABI_REGS, all=0
+       REG_L   t0, PT_EPC(sp)
+       REG_L   x1, PT_RA(sp)
+       REG_L   x10, PT_A0(sp)
+       REG_L   x11, PT_A1(sp)
+       REG_L   x12, PT_A2(sp)
+       REG_L   x13, PT_A3(sp)
+       REG_L   x14, PT_A4(sp)
+       REG_L   x15, PT_A5(sp)
+       REG_L   x16, PT_A6(sp)
+       REG_L   x17, PT_A7(sp)
+
+       .if \all == 1
+       REG_L   x2, PT_SP(sp)
+       REG_L   x3, PT_GP(sp)
+       REG_L   x4, PT_TP(sp)
+       REG_L   x6, PT_T1(sp)
+       REG_L   x7, PT_T2(sp)
+       REG_L   x8, PT_S0(sp)
+       REG_L   x9, PT_S1(sp)
+       REG_L   x18, PT_S2(sp)
+       REG_L   x19, PT_S3(sp)
+       REG_L   x20, PT_S4(sp)
+       REG_L   x21, PT_S5(sp)
+       REG_L   x22, PT_S6(sp)
+       REG_L   x23, PT_S7(sp)
+       REG_L   x24, PT_S8(sp)
+       REG_L   x25, PT_S9(sp)
+       REG_L   x26, PT_S10(sp)
+       REG_L   x27, PT_S11(sp)
+       REG_L   x28, PT_T3(sp)
+       REG_L   x29, PT_T4(sp)
+       REG_L   x30, PT_T5(sp)
+       REG_L   x31, PT_T6(sp)
+
+       .else
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+       REG_L   x8, PT_S0(sp)
+#endif
+       .endif
        addi    sp, sp, PT_SIZE_ON_STACK
        .endm
+
+       .macro PREPARE_ARGS
+       addi    a0, t0, -FENTRY_RA_OFFSET
+       la      a1, function_trace_op
+       REG_L   a2, 0(a1)
+       mv      a1, ra
+       mv      a3, sp
+       .endm
+
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
 
+#ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 SYM_FUNC_START(ftrace_caller)
        SAVE_ABI
 
@@ -105,34 +224,29 @@ SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL)
        call    ftrace_stub
 #endif
        RESTORE_ABI
-       jr t0
+       jr      t0
 SYM_FUNC_END(ftrace_caller)
 
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
 SYM_FUNC_START(ftrace_regs_caller)
-       SAVE_ALL
-
-       addi    a0, t0, -FENTRY_RA_OFFSET
-       la      a1, function_trace_op
-       REG_L   a2, 0(a1)
-       mv      a1, ra
-       mv      a3, sp
+       SAVE_ABI_REGS 1
+       PREPARE_ARGS
 
 SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
        call    ftrace_stub
 
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       addi    a0, sp, PT_RA
-       REG_L   a1, PT_EPC(sp)
-       addi    a1, a1, -FENTRY_RA_OFFSET
-#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
-       mv      a2, s0
-#endif
-SYM_INNER_LABEL(ftrace_graph_regs_call, SYM_L_GLOBAL)
+       RESTORE_ABI_REGS 1
+       jr      t0
+SYM_FUNC_END(ftrace_regs_caller)
+
+SYM_FUNC_START(ftrace_caller)
+       SAVE_ABI_REGS 0
+       PREPARE_ARGS
+
+SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
        call    ftrace_stub
-#endif
 
-       RESTORE_ALL
-       jr t0
-SYM_FUNC_END(ftrace_regs_caller)
+       RESTORE_ABI_REGS 0
+       jr      t0
+SYM_FUNC_END(ftrace_caller)
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */