From: Greg Kroah-Hartman Date: Tue, 11 Mar 2025 14:12:30 +0000 (+0100) Subject: drop some 6.13 patches for tracing X-Git-Tag: v5.4.291~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7e2b2ef872945652cdcd17e53e33cc95c80d7bf1;p=thirdparty%2Fkernel%2Fstable-queue.git drop some 6.13 patches for tracing Was disabling a config option :( --- diff --git a/queue-6.13/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch b/queue-6.13/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch deleted file mode 100644 index 6682a8c09e..0000000000 --- a/queue-6.13/fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch +++ /dev/null @@ -1,766 +0,0 @@ -From 8d08d4ef90d31596e14da03d051eaa3dc100344a Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 26 Dec 2024 14:11:55 +0900 -Subject: fgraph: Replace fgraph_ret_regs with ftrace_regs - -From: Masami Hiramatsu (Google) - -[ Upstream commit a3ed4157b7d89800a0008de0c9e46a438a5c3745 ] - -Use ftrace_regs instead of fgraph_ret_regs for tracing return value -on function_graph tracer because of simplifying the callback interface. - -The CONFIG_HAVE_FUNCTION_GRAPH_RETVAL is also replaced by -CONFIG_HAVE_FUNCTION_GRAPH_FREGS. - -Signed-off-by: Masami Hiramatsu (Google) -Acked-by: Heiko Carstens -Acked-by: Will Deacon -Cc: Catalin Marinas -Cc: Alexei Starovoitov -Cc: Florent Revest -Cc: Martin KaFai Lau -Cc: bpf -Cc: Alexei Starovoitov -Cc: Jiri Olsa -Cc: Alan Maguire -Cc: Mark Rutland -Cc: Huacai Chen -Cc: WANG Xuerui -Cc: Paul Walmsley -Cc: Palmer Dabbelt -Cc: Albert Ou -Cc: Vasily Gorbik -Cc: Alexander Gordeev -Cc: Heiko Carstens -Cc: Christian Borntraeger -Cc: Sven Schnelle -Cc: Thomas Gleixner -Cc: Ingo Molnar -Cc: Borislav Petkov -Cc: Dave Hansen -Cc: x86@kernel.org -Cc: "H. Peter Anvin" -Cc: Mathieu Desnoyers -Link: https://lore.kernel.org/173518991508.391279.16635322774382197642.stgit@devnote2 -Signed-off-by: Steven Rostedt (Google) -Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args") -Signed-off-by: Sasha Levin ---- - arch/arm64/Kconfig | 1 + - arch/arm64/include/asm/ftrace.h | 23 ++++++--------------- - arch/arm64/kernel/asm-offsets.c | 12 ----------- - arch/arm64/kernel/entry-ftrace.S | 32 ++++++++++++++++------------- - arch/loongarch/Kconfig | 2 +- - arch/loongarch/include/asm/ftrace.h | 26 ++++------------------- - arch/loongarch/kernel/asm-offsets.c | 12 ----------- - arch/loongarch/kernel/mcount.S | 17 ++++++++------- - arch/loongarch/kernel/mcount_dyn.S | 14 ++++++------- - arch/riscv/Kconfig | 2 +- - arch/riscv/include/asm/ftrace.h | 26 +++++------------------ - arch/riscv/kernel/mcount.S | 24 ++++++++++++---------- - arch/s390/Kconfig | 2 +- - arch/s390/include/asm/ftrace.h | 24 +++++++--------------- - arch/s390/kernel/asm-offsets.c | 6 ------ - arch/s390/kernel/mcount.S | 12 +++++------ - arch/x86/Kconfig | 2 +- - arch/x86/include/asm/ftrace.h | 20 ------------------ - arch/x86/kernel/ftrace_32.S | 13 ++++++------ - arch/x86/kernel/ftrace_64.S | 17 +++++++-------- - include/linux/ftrace.h | 12 ++++++++--- - include/linux/ftrace_regs.h | 2 ++ - kernel/trace/Kconfig | 4 ++-- - kernel/trace/fgraph.c | 21 ++++++++----------- - 24 files changed, 119 insertions(+), 207 deletions(-) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index 100570a048c5e..5f086777dad9b 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -219,6 +219,7 @@ config ARM64 - select HAVE_FTRACE_MCOUNT_RECORD - select HAVE_FUNCTION_TRACER - select HAVE_FUNCTION_ERROR_INJECTION -+ select HAVE_FUNCTION_GRAPH_FREGS - select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_GRAPH_RETVAL - select HAVE_GCC_PLUGINS -diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h -index 5ccff4de7f091..b5fa57b61378e 100644 ---- a/arch/arm64/include/asm/ftrace.h -+++ b/arch/arm64/include/asm/ftrace.h -@@ -129,6 +129,12 @@ ftrace_override_function_with_return(struct ftrace_regs *fregs) - arch_ftrace_regs(fregs)->pc = arch_ftrace_regs(fregs)->lr; - } - -+static __always_inline unsigned long -+ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) -+{ -+ return arch_ftrace_regs(fregs)->fp; -+} -+ - int ftrace_regs_query_register_offset(const char *name); - - int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); -@@ -186,23 +192,6 @@ static inline bool arch_syscall_match_sym_name(const char *sym, - - #ifndef __ASSEMBLY__ - #ifdef CONFIG_FUNCTION_GRAPH_TRACER --struct fgraph_ret_regs { -- /* x0 - x7 */ -- unsigned long regs[8]; -- -- unsigned long fp; -- unsigned long __unused; --}; -- --static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->regs[0]; --} -- --static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->fp; --} - - void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, - unsigned long frame_pointer); -diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c -index 29bf85dacffe1..eb1a840e4110f 100644 ---- a/arch/arm64/kernel/asm-offsets.c -+++ b/arch/arm64/kernel/asm-offsets.c -@@ -179,18 +179,6 @@ int main(void) - DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); - #endif - BLANK(); --#ifdef CONFIG_FUNCTION_GRAPH_TRACER -- DEFINE(FGRET_REGS_X0, offsetof(struct fgraph_ret_regs, regs[0])); -- DEFINE(FGRET_REGS_X1, offsetof(struct fgraph_ret_regs, regs[1])); -- DEFINE(FGRET_REGS_X2, offsetof(struct fgraph_ret_regs, regs[2])); -- DEFINE(FGRET_REGS_X3, offsetof(struct fgraph_ret_regs, regs[3])); -- DEFINE(FGRET_REGS_X4, offsetof(struct fgraph_ret_regs, regs[4])); -- DEFINE(FGRET_REGS_X5, offsetof(struct fgraph_ret_regs, regs[5])); -- DEFINE(FGRET_REGS_X6, offsetof(struct fgraph_ret_regs, regs[6])); -- DEFINE(FGRET_REGS_X7, offsetof(struct fgraph_ret_regs, regs[7])); -- DEFINE(FGRET_REGS_FP, offsetof(struct fgraph_ret_regs, fp)); -- DEFINE(FGRET_REGS_SIZE, sizeof(struct fgraph_ret_regs)); --#endif - #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - DEFINE(FTRACE_OPS_DIRECT_CALL, offsetof(struct ftrace_ops, direct_call)); - #endif -diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S -index f0c16640ef215..169ccf600066b 100644 ---- a/arch/arm64/kernel/entry-ftrace.S -+++ b/arch/arm64/kernel/entry-ftrace.S -@@ -329,24 +329,28 @@ SYM_FUNC_END(ftrace_stub_graph) - * @fp is checked against the value passed by ftrace_graph_caller(). - */ - SYM_CODE_START(return_to_handler) -- /* save return value regs */ -- sub sp, sp, #FGRET_REGS_SIZE -- stp x0, x1, [sp, #FGRET_REGS_X0] -- stp x2, x3, [sp, #FGRET_REGS_X2] -- stp x4, x5, [sp, #FGRET_REGS_X4] -- stp x6, x7, [sp, #FGRET_REGS_X6] -- str x29, [sp, #FGRET_REGS_FP] // parent's fp -+ /* Make room for ftrace_regs */ -+ sub sp, sp, #FREGS_SIZE -+ -+ /* Save return value regs */ -+ stp x0, x1, [sp, #FREGS_X0] -+ stp x2, x3, [sp, #FREGS_X2] -+ stp x4, x5, [sp, #FREGS_X4] -+ stp x6, x7, [sp, #FREGS_X6] -+ -+ /* Save the callsite's FP */ -+ str x29, [sp, #FREGS_FP] - - mov x0, sp -- bl ftrace_return_to_handler // addr = ftrace_return_to_hander(regs); -+ bl ftrace_return_to_handler // addr = ftrace_return_to_hander(fregs); - mov x30, x0 // restore the original return address - -- /* restore return value regs */ -- ldp x0, x1, [sp, #FGRET_REGS_X0] -- ldp x2, x3, [sp, #FGRET_REGS_X2] -- ldp x4, x5, [sp, #FGRET_REGS_X4] -- ldp x6, x7, [sp, #FGRET_REGS_X6] -- add sp, sp, #FGRET_REGS_SIZE -+ /* Restore return value regs */ -+ ldp x0, x1, [sp, #FREGS_X0] -+ ldp x2, x3, [sp, #FREGS_X2] -+ ldp x4, x5, [sp, #FREGS_X4] -+ ldp x6, x7, [sp, #FREGS_X6] -+ add sp, sp, #FREGS_SIZE - - ret - SYM_CODE_END(return_to_handler) -diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig -index dae3a9104ca65..49f5bfc00e5a1 100644 ---- a/arch/loongarch/Kconfig -+++ b/arch/loongarch/Kconfig -@@ -137,7 +137,7 @@ config LOONGARCH - select HAVE_FTRACE_MCOUNT_RECORD - select HAVE_FUNCTION_ARG_ACCESS_API - select HAVE_FUNCTION_ERROR_INJECTION -- select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER -+ select HAVE_FUNCTION_GRAPH_FREGS - select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_TRACER - select HAVE_GCC_PLUGINS -diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h -index 8f13eaeaa3251..ceb3e3d9c0d3d 100644 ---- a/arch/loongarch/include/asm/ftrace.h -+++ b/arch/loongarch/include/asm/ftrace.h -@@ -57,6 +57,10 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) - instruction_pointer_set(&arch_ftrace_regs(fregs)->regs, ip); - } - -+#undef ftrace_regs_get_frame_pointer -+#define ftrace_regs_get_frame_pointer(fregs) \ -+ (arch_ftrace_regs(fregs)->regs.regs[22]) -+ - #define ftrace_graph_func ftrace_graph_func - void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *fregs); -@@ -78,26 +82,4 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) - - #endif /* CONFIG_FUNCTION_TRACER */ - --#ifndef __ASSEMBLY__ --#ifdef CONFIG_FUNCTION_GRAPH_TRACER --struct fgraph_ret_regs { -- /* a0 - a1 */ -- unsigned long regs[2]; -- -- unsigned long fp; -- unsigned long __unused; --}; -- --static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->regs[0]; --} -- --static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->fp; --} --#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ --#endif -- - #endif /* _ASM_LOONGARCH_FTRACE_H */ -diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c -index 049c5c3e370cb..8be1c38ad8eb2 100644 ---- a/arch/loongarch/kernel/asm-offsets.c -+++ b/arch/loongarch/kernel/asm-offsets.c -@@ -280,18 +280,6 @@ static void __used output_pbe_defines(void) - } - #endif - --#ifdef CONFIG_FUNCTION_GRAPH_TRACER --static void __used output_fgraph_ret_regs_defines(void) --{ -- COMMENT("LoongArch fgraph_ret_regs offsets."); -- OFFSET(FGRET_REGS_A0, fgraph_ret_regs, regs[0]); -- OFFSET(FGRET_REGS_A1, fgraph_ret_regs, regs[1]); -- OFFSET(FGRET_REGS_FP, fgraph_ret_regs, fp); -- DEFINE(FGRET_REGS_SIZE, sizeof(struct fgraph_ret_regs)); -- BLANK(); --} --#endif -- - static void __used output_kvm_defines(void) - { - COMMENT("KVM/LoongArch Specific offsets."); -diff --git a/arch/loongarch/kernel/mcount.S b/arch/loongarch/kernel/mcount.S -index 3015896016a0b..b6850503e061b 100644 ---- a/arch/loongarch/kernel/mcount.S -+++ b/arch/loongarch/kernel/mcount.S -@@ -79,10 +79,11 @@ SYM_FUNC_START(ftrace_graph_caller) - SYM_FUNC_END(ftrace_graph_caller) - - SYM_FUNC_START(return_to_handler) -- PTR_ADDI sp, sp, -FGRET_REGS_SIZE -- PTR_S a0, sp, FGRET_REGS_A0 -- PTR_S a1, sp, FGRET_REGS_A1 -- PTR_S zero, sp, FGRET_REGS_FP -+ /* Save return value regs */ -+ PTR_ADDI sp, sp, -PT_SIZE -+ PTR_S a0, sp, PT_R4 -+ PTR_S a1, sp, PT_R5 -+ PTR_S zero, sp, PT_R22 - - move a0, sp - bl ftrace_return_to_handler -@@ -90,9 +91,11 @@ SYM_FUNC_START(return_to_handler) - /* Restore the real parent address: a0 -> ra */ - move ra, a0 - -- PTR_L a0, sp, FGRET_REGS_A0 -- PTR_L a1, sp, FGRET_REGS_A1 -- PTR_ADDI sp, sp, FGRET_REGS_SIZE -+ /* Restore return value regs */ -+ PTR_L a0, sp, PT_R4 -+ PTR_L a1, sp, PT_R5 -+ PTR_ADDI sp, sp, PT_SIZE -+ - jr ra - SYM_FUNC_END(return_to_handler) - #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S -index 0c65cf09110cd..d6b474ad1d5e5 100644 ---- a/arch/loongarch/kernel/mcount_dyn.S -+++ b/arch/loongarch/kernel/mcount_dyn.S -@@ -140,19 +140,19 @@ SYM_CODE_END(ftrace_graph_caller) - SYM_CODE_START(return_to_handler) - UNWIND_HINT_UNDEFINED - /* Save return value regs */ -- PTR_ADDI sp, sp, -FGRET_REGS_SIZE -- PTR_S a0, sp, FGRET_REGS_A0 -- PTR_S a1, sp, FGRET_REGS_A1 -- PTR_S zero, sp, FGRET_REGS_FP -+ PTR_ADDI sp, sp, -PT_SIZE -+ PTR_S a0, sp, PT_R4 -+ PTR_S a1, sp, PT_R5 -+ PTR_S zero, sp, PT_R22 - - move a0, sp - bl ftrace_return_to_handler - move ra, a0 - - /* Restore return value regs */ -- PTR_L a0, sp, FGRET_REGS_A0 -- PTR_L a1, sp, FGRET_REGS_A1 -- PTR_ADDI sp, sp, FGRET_REGS_SIZE -+ PTR_L a0, sp, PT_R4 -+ PTR_L a1, sp, PT_R5 -+ PTR_ADDI sp, sp, PT_SIZE - - jr ra - SYM_CODE_END(return_to_handler) -diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig -index d4a7ca0388c07..1e807c61258fb 100644 ---- a/arch/riscv/Kconfig -+++ b/arch/riscv/Kconfig -@@ -148,7 +148,7 @@ config RISCV - select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE - select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL - select HAVE_FUNCTION_GRAPH_TRACER -- select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER -+ select HAVE_FUNCTION_GRAPH_FREGS - select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION - select HAVE_EBPF_JIT if MMU - select HAVE_GUP_FAST if MMU -diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h -index 3d66437a10297..9372f8d7036f8 100644 ---- a/arch/riscv/include/asm/ftrace.h -+++ b/arch/riscv/include/asm/ftrace.h -@@ -168,6 +168,11 @@ static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct - return arch_ftrace_regs(fregs)->sp; - } - -+static __always_inline unsigned long ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) -+{ -+ return arch_ftrace_regs(fregs)->s0; -+} -+ - static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs, - unsigned int n) - { -@@ -208,25 +213,4 @@ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsi - - #endif /* CONFIG_DYNAMIC_FTRACE */ - --#ifndef __ASSEMBLY__ --#ifdef CONFIG_FUNCTION_GRAPH_TRACER --struct fgraph_ret_regs { -- unsigned long a1; -- unsigned long a0; -- unsigned long s0; -- unsigned long ra; --}; -- --static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->a0; --} -- --static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->s0; --} --#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ --#endif -- - #endif /* _ASM_RISCV_FTRACE_H */ -diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S -index 3a42f6287909d..068168046e0ef 100644 ---- a/arch/riscv/kernel/mcount.S -+++ b/arch/riscv/kernel/mcount.S -@@ -12,6 +12,8 @@ - #include - #include - -+#define ABI_SIZE_ON_STACK 80 -+ - .text - - .macro SAVE_ABI_STATE -@@ -26,12 +28,12 @@ - * register if a0 was not saved. - */ - .macro SAVE_RET_ABI_STATE -- addi sp, sp, -4*SZREG -- REG_S s0, 2*SZREG(sp) -- REG_S ra, 3*SZREG(sp) -- REG_S a0, 1*SZREG(sp) -- REG_S a1, 0*SZREG(sp) -- addi s0, sp, 4*SZREG -+ addi sp, sp, -ABI_SIZE_ON_STACK -+ REG_S ra, 1*SZREG(sp) -+ REG_S s0, 8*SZREG(sp) -+ REG_S a0, 10*SZREG(sp) -+ REG_S a1, 11*SZREG(sp) -+ addi s0, sp, ABI_SIZE_ON_STACK - .endm - - .macro RESTORE_ABI_STATE -@@ -41,11 +43,11 @@ - .endm - - .macro RESTORE_RET_ABI_STATE -- REG_L ra, 3*SZREG(sp) -- REG_L s0, 2*SZREG(sp) -- REG_L a0, 1*SZREG(sp) -- REG_L a1, 0*SZREG(sp) -- addi sp, sp, 4*SZREG -+ REG_L ra, 1*SZREG(sp) -+ REG_L s0, 8*SZREG(sp) -+ REG_L a0, 10*SZREG(sp) -+ REG_L a1, 11*SZREG(sp) -+ addi sp, sp, ABI_SIZE_ON_STACK - .endm - - SYM_TYPED_FUNC_START(ftrace_stub) -diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig -index 83b1d7bbd8880..a8cecae74fe81 100644 ---- a/arch/s390/Kconfig -+++ b/arch/s390/Kconfig -@@ -193,7 +193,7 @@ config S390 - select HAVE_FTRACE_MCOUNT_RECORD - select HAVE_FUNCTION_ARG_ACCESS_API - select HAVE_FUNCTION_ERROR_INJECTION -- select HAVE_FUNCTION_GRAPH_RETVAL -+ select HAVE_FUNCTION_GRAPH_FREGS - select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_TRACER - select HAVE_GCC_PLUGINS -diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h -index fc97d75dc752c..5c94c1fc1bc1c 100644 ---- a/arch/s390/include/asm/ftrace.h -+++ b/arch/s390/include/asm/ftrace.h -@@ -62,23 +62,6 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs * - return NULL; - } - --#ifdef CONFIG_FUNCTION_GRAPH_TRACER --struct fgraph_ret_regs { -- unsigned long gpr2; -- unsigned long fp; --}; -- --static __always_inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->gpr2; --} -- --static __always_inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->fp; --} --#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -- - static __always_inline void - ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, - unsigned long ip) -@@ -86,6 +69,13 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, - arch_ftrace_regs(fregs)->regs.psw.addr = ip; - } - -+#undef ftrace_regs_get_frame_pointer -+static __always_inline unsigned long -+ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs) -+{ -+ return ftrace_regs_get_stack_pointer(fregs); -+} -+ - #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - /* - * When an ftrace registered caller is tracing a function that is -diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c -index 862a9140528e9..36709112ae7a2 100644 ---- a/arch/s390/kernel/asm-offsets.c -+++ b/arch/s390/kernel/asm-offsets.c -@@ -175,12 +175,6 @@ int main(void) - DEFINE(OLDMEM_SIZE, PARMAREA + offsetof(struct parmarea, oldmem_size)); - DEFINE(COMMAND_LINE, PARMAREA + offsetof(struct parmarea, command_line)); - DEFINE(MAX_COMMAND_LINE_SIZE, PARMAREA + offsetof(struct parmarea, max_command_line_size)); --#ifdef CONFIG_FUNCTION_GRAPH_TRACER -- /* function graph return value tracing */ -- OFFSET(__FGRAPH_RET_GPR2, fgraph_ret_regs, gpr2); -- OFFSET(__FGRAPH_RET_FP, fgraph_ret_regs, fp); -- DEFINE(__FGRAPH_RET_SIZE, sizeof(struct fgraph_ret_regs)); --#endif - OFFSET(__FTRACE_REGS_PT_REGS, __arch_ftrace_regs, regs); - DEFINE(__FTRACE_REGS_SIZE, sizeof(struct __arch_ftrace_regs)); - -diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S -index 7e267ef63a7fe..2b628aa3d8095 100644 ---- a/arch/s390/kernel/mcount.S -+++ b/arch/s390/kernel/mcount.S -@@ -134,14 +134,14 @@ SYM_CODE_END(ftrace_common) - SYM_FUNC_START(return_to_handler) - stmg %r2,%r5,32(%r15) - lgr %r1,%r15 -- aghi %r15,-(STACK_FRAME_OVERHEAD+__FGRAPH_RET_SIZE) -+ # allocate ftrace_regs and stack frame for ftrace_return_to_handler -+ aghi %r15,-STACK_FRAME_SIZE_FREGS - stg %r1,__SF_BACKCHAIN(%r15) -- la %r3,STACK_FRAME_OVERHEAD(%r15) -- stg %r1,__FGRAPH_RET_FP(%r3) -- stg %r2,__FGRAPH_RET_GPR2(%r3) -- lgr %r2,%r3 -+ stg %r2,(STACK_FREGS_PTREGS_GPRS+2*8)(%r15) -+ stg %r1,(STACK_FREGS_PTREGS_GPRS+15*8)(%r15) -+ la %r2,STACK_FRAME_OVERHEAD(%r15) - brasl %r14,ftrace_return_to_handler -- aghi %r15,STACK_FRAME_OVERHEAD+__FGRAPH_RET_SIZE -+ aghi %r15,STACK_FRAME_SIZE_FREGS - lgr %r14,%r2 - lmg %r2,%r5,32(%r15) - BR_EX %r14 -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 757333fe82c76..aa317f6064b89 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -234,7 +234,7 @@ config X86 - select HAVE_GUP_FAST - select HAVE_FENTRY if X86_64 || DYNAMIC_FTRACE - select HAVE_FTRACE_MCOUNT_RECORD -- select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER -+ select HAVE_FUNCTION_GRAPH_FREGS if HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_GRAPH_TRACER if X86_32 || (X86_64 && DYNAMIC_FTRACE) - select HAVE_FUNCTION_TRACER - select HAVE_GCC_PLUGINS -diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h -index 6e8cf0fa48fc6..d61407c680c28 100644 ---- a/arch/x86/include/asm/ftrace.h -+++ b/arch/x86/include/asm/ftrace.h -@@ -134,24 +134,4 @@ static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) - #endif /* !COMPILE_OFFSETS */ - #endif /* !__ASSEMBLY__ */ - --#ifndef __ASSEMBLY__ --#ifdef CONFIG_FUNCTION_GRAPH_TRACER --struct fgraph_ret_regs { -- unsigned long ax; -- unsigned long dx; -- unsigned long bp; --}; -- --static inline unsigned long fgraph_ret_regs_return_value(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->ax; --} -- --static inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph_ret_regs *ret_regs) --{ -- return ret_regs->bp; --} --#endif /* ifdef CONFIG_FUNCTION_GRAPH_TRACER */ --#endif -- - #endif /* _ASM_X86_FTRACE_H */ -diff --git a/arch/x86/kernel/ftrace_32.S b/arch/x86/kernel/ftrace_32.S -index 58d9ed50fe617..f4e0c33612342 100644 ---- a/arch/x86/kernel/ftrace_32.S -+++ b/arch/x86/kernel/ftrace_32.S -@@ -187,14 +187,15 @@ SYM_CODE_END(ftrace_graph_caller) - - .globl return_to_handler - return_to_handler: -- pushl $0 -- pushl %edx -- pushl %eax -+ subl $(PTREGS_SIZE), %esp -+ movl $0, PT_EBP(%esp) -+ movl %edx, PT_EDX(%esp) -+ movl %eax, PT_EAX(%esp) - movl %esp, %eax - call ftrace_return_to_handler - movl %eax, %ecx -- popl %eax -- popl %edx -- addl $4, %esp # skip ebp -+ movl PT_EAX(%esp), %eax -+ movl PT_EDX(%esp), %edx -+ addl $(PTREGS_SIZE), %esp - JMP_NOSPEC ecx - #endif -diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S -index 214f30e9f0c01..d516472285967 100644 ---- a/arch/x86/kernel/ftrace_64.S -+++ b/arch/x86/kernel/ftrace_64.S -@@ -348,21 +348,22 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__) - SYM_CODE_START(return_to_handler) - UNWIND_HINT_UNDEFINED - ANNOTATE_NOENDBR -- subq $24, %rsp - -- /* Save the return values */ -- movq %rax, (%rsp) -- movq %rdx, 8(%rsp) -- movq %rbp, 16(%rsp) -+ /* Save ftrace_regs for function exit context */ -+ subq $(FRAME_SIZE), %rsp -+ -+ movq %rax, RAX(%rsp) -+ movq %rdx, RDX(%rsp) -+ movq %rbp, RBP(%rsp) - movq %rsp, %rdi - - call ftrace_return_to_handler - - movq %rax, %rdi -- movq 8(%rsp), %rdx -- movq (%rsp), %rax -+ movq RDX(%rsp), %rdx -+ movq RAX(%rsp), %rax - -- addq $24, %rsp -+ addq $(FRAME_SIZE), %rsp - /* - * Jump back to the old return address. This cannot be JMP_NOSPEC rdi - * since IBT would demand that contain ENDBR, which simply isn't so for -diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h -index aa9ddd1e4bb6a..b7407004c799e 100644 ---- a/include/linux/ftrace.h -+++ b/include/linux/ftrace.h -@@ -43,9 +43,8 @@ struct dyn_ftrace; - - char *arch_ftrace_match_adjust(char *str, const char *search); - --#ifdef CONFIG_HAVE_FUNCTION_GRAPH_RETVAL --struct fgraph_ret_regs; --unsigned long ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs); -+#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS -+unsigned long ftrace_return_to_handler(struct ftrace_regs *fregs); - #else - unsigned long ftrace_return_to_handler(unsigned long frame_pointer); - #endif -@@ -134,6 +133,13 @@ extern int ftrace_enabled; - * Also, architecture dependent fields can be used for internal process. - * (e.g. orig_ax on x86_64) - * -+ * Basically, ftrace_regs stores the registers related to the context. -+ * On function entry, registers for function parameters and hooking the -+ * function call are stored, and on function exit, registers for function -+ * return value and frame pointers are stored. -+ * -+ * And also, it dpends on the context that which registers are restored -+ * from the ftrace_regs. - * On the function entry, those registers will be restored except for - * the stack pointer, so that user can change the function parameters - * and instruction pointer (e.g. live patching.) -diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h -index be1ed0c891d07..bbc1873ca6b8e 100644 ---- a/include/linux/ftrace_regs.h -+++ b/include/linux/ftrace_regs.h -@@ -30,6 +30,8 @@ struct ftrace_regs; - override_function_with_return(&arch_ftrace_regs(fregs)->regs) - #define ftrace_regs_query_register_offset(name) \ - regs_query_register_offset(name) -+#define ftrace_regs_get_frame_pointer(fregs) \ -+ frame_pointer(&arch_ftrace_regs(fregs)->regs) - - #endif /* HAVE_ARCH_FTRACE_REGS */ - -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index 74c2b1d43bb98..c5ab2a561272d 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -31,7 +31,7 @@ config HAVE_FUNCTION_GRAPH_TRACER - help - See Documentation/trace/ftrace-design.rst - --config HAVE_FUNCTION_GRAPH_RETVAL -+config HAVE_FUNCTION_GRAPH_FREGS - bool - - config HAVE_DYNAMIC_FTRACE -@@ -232,7 +232,7 @@ config FUNCTION_GRAPH_TRACER - - config FUNCTION_GRAPH_RETVAL - bool "Kernel Function Graph Return Value" -- depends on HAVE_FUNCTION_GRAPH_RETVAL -+ depends on HAVE_FUNCTION_GRAPH_FREGS - depends on FUNCTION_GRAPH_TRACER - default n - help -diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c -index 30e3ddc8a8a84..6e55759b45776 100644 ---- a/kernel/trace/fgraph.c -+++ b/kernel/trace/fgraph.c -@@ -792,15 +792,12 @@ static struct notifier_block ftrace_suspend_notifier = { - .notifier_call = ftrace_suspend_notifier_call, - }; - --/* fgraph_ret_regs is not defined without CONFIG_FUNCTION_GRAPH_RETVAL */ --struct fgraph_ret_regs; -- - /* - * Send the trace to the ring-buffer. - * @return the original return address. - */ --static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs, -- unsigned long frame_pointer) -+static inline unsigned long -+__ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointer) - { - struct ftrace_ret_stack *ret_stack; - struct ftrace_graph_ret trace; -@@ -820,7 +817,7 @@ static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs - - trace.rettime = trace_clock_local(); - #ifdef CONFIG_FUNCTION_GRAPH_RETVAL -- trace.retval = fgraph_ret_regs_return_value(ret_regs); -+ trace.retval = ftrace_regs_get_return_value(fregs); - #endif - - bitmap = get_bitmap_bits(current, offset); -@@ -855,14 +852,14 @@ static unsigned long __ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs - } - - /* -- * After all architecures have selected HAVE_FUNCTION_GRAPH_RETVAL, we can -- * leave only ftrace_return_to_handler(ret_regs). -+ * After all architecures have selected HAVE_FUNCTION_GRAPH_FREGS, we can -+ * leave only ftrace_return_to_handler(fregs). - */ --#ifdef CONFIG_HAVE_FUNCTION_GRAPH_RETVAL --unsigned long ftrace_return_to_handler(struct fgraph_ret_regs *ret_regs) -+#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS -+unsigned long ftrace_return_to_handler(struct ftrace_regs *fregs) - { -- return __ftrace_return_to_handler(ret_regs, -- fgraph_ret_regs_frame_pointer(ret_regs)); -+ return __ftrace_return_to_handler(fregs, -+ ftrace_regs_get_frame_pointer(fregs)); - } - #else - unsigned long ftrace_return_to_handler(unsigned long frame_pointer) --- -2.39.5 - diff --git a/queue-6.13/fprobe-rewrite-fprobe-on-function-graph-tracer.patch b/queue-6.13/fprobe-rewrite-fprobe-on-function-graph-tracer.patch deleted file mode 100644 index 04302feece..0000000000 --- a/queue-6.13/fprobe-rewrite-fprobe-on-function-graph-tracer.patch +++ /dev/null @@ -1,1168 +0,0 @@ -From 98b2c6a182a85ab61910f92b12b78f066e34fd38 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 26 Dec 2024 14:13:59 +0900 -Subject: fprobe: Rewrite fprobe on function-graph tracer - -From: Masami Hiramatsu (Google) - -[ Upstream commit 4346ba1604093305a287e08eb465a9c15ba05b80 ] - -Rewrite fprobe implementation on function-graph tracer. -Major API changes are: - - 'nr_maxactive' field is deprecated. - - This depends on CONFIG_DYNAMIC_FTRACE_WITH_ARGS or - !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS, and - CONFIG_HAVE_FUNCTION_GRAPH_FREGS. So currently works only - on x86_64. - - Currently the entry size is limited in 15 * sizeof(long). - - If there is too many fprobe exit handler set on the same - function, it will fail to probe. - -Signed-off-by: Masami Hiramatsu (Google) -Acked-by: Heiko Carstens # s390 -Cc: Alexei Starovoitov -Cc: Florent Revest -Cc: Martin KaFai Lau -Cc: bpf -Cc: Alexei Starovoitov -Cc: Jiri Olsa -Cc: Alan Maguire -Cc: Heiko Carstens -Cc: Mark Rutland -Cc: Catalin Marinas -Cc: Will Deacon -Cc: Huacai Chen -Cc: WANG Xuerui -Cc: Michael Ellerman -Cc: Nicholas Piggin -Cc: Christophe Leroy -Cc: Naveen N Rao -Cc: Madhavan Srinivasan -Cc: Paul Walmsley -Cc: Palmer Dabbelt -Cc: Albert Ou -Cc: Vasily Gorbik -Cc: Alexander Gordeev -Cc: Christian Borntraeger -Cc: Sven Schnelle -Cc: Thomas Gleixner -Cc: Ingo Molnar -Cc: Borislav Petkov -Cc: Dave Hansen -Cc: x86@kernel.org -Cc: "H. Peter Anvin" -Cc: Mathieu Desnoyers -Cc: Andrew Morton -Link: https://lore.kernel.org/173519003970.391279.14406792285453830996.stgit@devnote2 -Signed-off-by: Steven Rostedt (Google) -Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args") -Signed-off-by: Sasha Levin ---- - arch/arm64/include/asm/ftrace.h | 6 + - arch/loongarch/include/asm/ftrace.h | 6 + - arch/powerpc/include/asm/ftrace.h | 6 + - arch/riscv/include/asm/ftrace.h | 5 + - arch/s390/include/asm/ftrace.h | 6 + - arch/x86/include/asm/ftrace.h | 6 + - include/linux/fprobe.h | 58 ++- - kernel/trace/Kconfig | 8 +- - kernel/trace/fprobe.c | 637 ++++++++++++++++++++-------- - lib/test_fprobe.c | 45 -- - 10 files changed, 538 insertions(+), 245 deletions(-) - -diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h -index 10e56522122aa..876e88ad4119f 100644 ---- a/arch/arm64/include/asm/ftrace.h -+++ b/arch/arm64/include/asm/ftrace.h -@@ -135,6 +135,12 @@ ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) - return arch_ftrace_regs(fregs)->fp; - } - -+static __always_inline unsigned long -+ftrace_regs_get_return_address(const struct ftrace_regs *fregs) -+{ -+ return arch_ftrace_regs(fregs)->lr; -+} -+ - static __always_inline struct pt_regs * - ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) - { -diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h -index ceb3e3d9c0d3d..6e0a99763a9a7 100644 ---- a/arch/loongarch/include/asm/ftrace.h -+++ b/arch/loongarch/include/asm/ftrace.h -@@ -61,6 +61,12 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) - #define ftrace_regs_get_frame_pointer(fregs) \ - (arch_ftrace_regs(fregs)->regs.regs[22]) - -+static __always_inline unsigned long -+ftrace_regs_get_return_address(struct ftrace_regs *fregs) -+{ -+ return *(unsigned long *)(arch_ftrace_regs(fregs)->regs.regs[1]); -+} -+ - #define ftrace_graph_func ftrace_graph_func - void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct ftrace_regs *fregs); -diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h -index fe181bafdca4f..82da7c7a1d125 100644 ---- a/arch/powerpc/include/asm/ftrace.h -+++ b/arch/powerpc/include/asm/ftrace.h -@@ -57,6 +57,12 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, - regs_set_return_ip(&arch_ftrace_regs(fregs)->regs, ip); - } - -+static __always_inline unsigned long -+ftrace_regs_get_return_address(struct ftrace_regs *fregs) -+{ -+ return arch_ftrace_regs(fregs)->regs.link; -+} -+ - struct ftrace_ops; - - #define ftrace_graph_func ftrace_graph_func -diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h -index 7064a530794b6..c4721ce44ca47 100644 ---- a/arch/riscv/include/asm/ftrace.h -+++ b/arch/riscv/include/asm/ftrace.h -@@ -186,6 +186,11 @@ static __always_inline unsigned long ftrace_regs_get_return_value(const struct f - return arch_ftrace_regs(fregs)->a0; - } - -+static __always_inline unsigned long ftrace_regs_get_return_address(const struct ftrace_regs *fregs) -+{ -+ return arch_ftrace_regs(fregs)->ra; -+} -+ - static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs, - unsigned long ret) - { -diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h -index 5b7cb49c41ee0..8c94a330c70c9 100644 ---- a/arch/s390/include/asm/ftrace.h -+++ b/arch/s390/include/asm/ftrace.h -@@ -76,6 +76,12 @@ ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs) - return ftrace_regs_get_stack_pointer(fregs); - } - -+static __always_inline unsigned long -+ftrace_regs_get_return_address(const struct ftrace_regs *fregs) -+{ -+ return arch_ftrace_regs(fregs)->regs.gprs[14]; -+} -+ - #define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ - (_regs)->psw.mask = 0; \ - (_regs)->psw.addr = arch_ftrace_regs(fregs)->regs.psw.addr; \ -diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h -index 7e06f8c7937aa..cc92c99ef2760 100644 ---- a/arch/x86/include/asm/ftrace.h -+++ b/arch/x86/include/asm/ftrace.h -@@ -58,6 +58,12 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) - do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) - - -+static __always_inline unsigned long -+ftrace_regs_get_return_address(struct ftrace_regs *fregs) -+{ -+ return *(unsigned long *)ftrace_regs_get_stack_pointer(fregs); -+} -+ - struct ftrace_ops; - #define ftrace_graph_func ftrace_graph_func - void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, -diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h -index ef609bcca0f92..91337bcb452ff 100644 ---- a/include/linux/fprobe.h -+++ b/include/linux/fprobe.h -@@ -5,10 +5,11 @@ - - #include - #include --#include -+#include -+#include -+#include - - struct fprobe; -- - typedef int (*fprobe_entry_cb)(struct fprobe *fp, unsigned long entry_ip, - unsigned long ret_ip, struct ftrace_regs *regs, - void *entry_data); -@@ -17,35 +18,57 @@ typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip, - unsigned long ret_ip, struct ftrace_regs *regs, - void *entry_data); - -+/** -+ * struct fprobe_hlist_node - address based hash list node for fprobe. -+ * -+ * @hlist: The hlist node for address search hash table. -+ * @addr: One of the probing address of @fp. -+ * @fp: The fprobe which owns this. -+ */ -+struct fprobe_hlist_node { -+ struct hlist_node hlist; -+ unsigned long addr; -+ struct fprobe *fp; -+}; -+ -+/** -+ * struct fprobe_hlist - hash list nodes for fprobe. -+ * -+ * @hlist: The hlist node for existence checking hash table. -+ * @rcu: rcu_head for RCU deferred release. -+ * @fp: The fprobe which owns this fprobe_hlist. -+ * @size: The size of @array. -+ * @array: The fprobe_hlist_node for each address to probe. -+ */ -+struct fprobe_hlist { -+ struct hlist_node hlist; -+ struct rcu_head rcu; -+ struct fprobe *fp; -+ int size; -+ struct fprobe_hlist_node array[] __counted_by(size); -+}; -+ - /** - * struct fprobe - ftrace based probe. -- * @ops: The ftrace_ops. -+ * - * @nmissed: The counter for missing events. - * @flags: The status flag. -- * @rethook: The rethook data structure. (internal data) - * @entry_data_size: The private data storage size. -- * @nr_maxactive: The max number of active functions. -+ * @nr_maxactive: The max number of active functions. (*deprecated) - * @entry_handler: The callback function for function entry. - * @exit_handler: The callback function for function exit. -+ * @hlist_array: The fprobe_hlist for fprobe search from IP hash table. - */ - struct fprobe { --#ifdef CONFIG_FUNCTION_TRACER -- /* -- * If CONFIG_FUNCTION_TRACER is not set, CONFIG_FPROBE is disabled too. -- * But user of fprobe may keep embedding the struct fprobe on their own -- * code. To avoid build error, this will keep the fprobe data structure -- * defined here, but remove ftrace_ops data structure. -- */ -- struct ftrace_ops ops; --#endif - unsigned long nmissed; - unsigned int flags; -- struct rethook *rethook; - size_t entry_data_size; - int nr_maxactive; - - fprobe_entry_cb entry_handler; - fprobe_exit_cb exit_handler; -+ -+ struct fprobe_hlist *hlist_array; - }; - - /* This fprobe is soft-disabled. */ -@@ -121,4 +144,9 @@ static inline void enable_fprobe(struct fprobe *fp) - fp->flags &= ~FPROBE_FL_DISABLED; - } - -+/* The entry data size is 4 bits (=16) * sizeof(long) in maximum */ -+#define FPROBE_DATA_SIZE_BITS 4 -+#define MAX_FPROBE_DATA_SIZE_WORD ((1L << FPROBE_DATA_SIZE_BITS) - 1) -+#define MAX_FPROBE_DATA_SIZE (MAX_FPROBE_DATA_SIZE_WORD * sizeof(long)) -+ - #endif -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index 7f8165f2049a5..69954212c77d1 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -302,11 +302,9 @@ config DYNAMIC_FTRACE_WITH_ARGS - - config FPROBE - bool "Kernel Function Probe (fprobe)" -- depends on FUNCTION_TRACER -- depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS -- depends on HAVE_FTRACE_REGS_HAVING_PT_REGS || !HAVE_DYNAMIC_FTRACE_WITH_ARGS -- depends on HAVE_RETHOOK -- select RETHOOK -+ depends on HAVE_FUNCTION_GRAPH_FREGS && HAVE_FTRACE_GRAPH_FUNC -+ depends on DYNAMIC_FTRACE_WITH_ARGS -+ select FUNCTION_GRAPH_TRACER - default n - help - This option enables kernel function probe (fprobe) based on ftrace. -diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c -index 90a3c8e2bbdf1..ed9c1d79426a2 100644 ---- a/kernel/trace/fprobe.c -+++ b/kernel/trace/fprobe.c -@@ -8,98 +8,195 @@ - #include - #include - #include --#include -+#include -+#include - #include - #include - - #include "trace.h" - --struct fprobe_rethook_node { -- struct rethook_node node; -- unsigned long entry_ip; -- unsigned long entry_parent_ip; -- char data[]; --}; -+#define FPROBE_IP_HASH_BITS 8 -+#define FPROBE_IP_TABLE_SIZE (1 << FPROBE_IP_HASH_BITS) - --static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip, -- struct ftrace_ops *ops, struct ftrace_regs *fregs) --{ -- struct fprobe_rethook_node *fpr; -- struct rethook_node *rh = NULL; -- struct fprobe *fp; -- void *entry_data = NULL; -- int ret = 0; -+#define FPROBE_HASH_BITS 6 -+#define FPROBE_TABLE_SIZE (1 << FPROBE_HASH_BITS) - -- fp = container_of(ops, struct fprobe, ops); -+#define SIZE_IN_LONG(x) ((x + sizeof(long) - 1) >> (sizeof(long) == 8 ? 3 : 2)) - -- if (fp->exit_handler) { -- rh = rethook_try_get(fp->rethook); -- if (!rh) { -- fp->nmissed++; -- return; -- } -- fpr = container_of(rh, struct fprobe_rethook_node, node); -- fpr->entry_ip = ip; -- fpr->entry_parent_ip = parent_ip; -- if (fp->entry_data_size) -- entry_data = fpr->data; -+/* -+ * fprobe_table: hold 'fprobe_hlist::hlist' for checking the fprobe still -+ * exists. The key is the address of fprobe instance. -+ * fprobe_ip_table: hold 'fprobe_hlist::array[*]' for searching the fprobe -+ * instance related to the funciton address. The key is the ftrace IP -+ * address. -+ * -+ * When unregistering the fprobe, fprobe_hlist::fp and fprobe_hlist::array[*].fp -+ * are set NULL and delete those from both hash tables (by hlist_del_rcu). -+ * After an RCU grace period, the fprobe_hlist itself will be released. -+ * -+ * fprobe_table and fprobe_ip_table can be accessed from either -+ * - Normal hlist traversal and RCU add/del under 'fprobe_mutex' is held. -+ * - RCU hlist traversal under disabling preempt -+ */ -+static struct hlist_head fprobe_table[FPROBE_TABLE_SIZE]; -+static struct hlist_head fprobe_ip_table[FPROBE_IP_TABLE_SIZE]; -+static DEFINE_MUTEX(fprobe_mutex); -+ -+/* -+ * Find first fprobe in the hlist. It will be iterated twice in the entry -+ * probe, once for correcting the total required size, the second time is -+ * calling back the user handlers. -+ * Thus the hlist in the fprobe_table must be sorted and new probe needs to -+ * be added *before* the first fprobe. -+ */ -+static struct fprobe_hlist_node *find_first_fprobe_node(unsigned long ip) -+{ -+ struct fprobe_hlist_node *node; -+ struct hlist_head *head; -+ -+ head = &fprobe_ip_table[hash_ptr((void *)ip, FPROBE_IP_HASH_BITS)]; -+ hlist_for_each_entry_rcu(node, head, hlist, -+ lockdep_is_held(&fprobe_mutex)) { -+ if (node->addr == ip) -+ return node; - } -+ return NULL; -+} -+NOKPROBE_SYMBOL(find_first_fprobe_node); - -- if (fp->entry_handler) -- ret = fp->entry_handler(fp, ip, parent_ip, fregs, entry_data); -+/* Node insertion and deletion requires the fprobe_mutex */ -+static void insert_fprobe_node(struct fprobe_hlist_node *node) -+{ -+ unsigned long ip = node->addr; -+ struct fprobe_hlist_node *next; -+ struct hlist_head *head; - -- /* If entry_handler returns !0, nmissed is not counted. */ -- if (rh) { -- if (ret) -- rethook_recycle(rh); -- else -- rethook_hook(rh, ftrace_get_regs(fregs), true); -+ lockdep_assert_held(&fprobe_mutex); -+ -+ next = find_first_fprobe_node(ip); -+ if (next) { -+ hlist_add_before_rcu(&node->hlist, &next->hlist); -+ return; - } -+ head = &fprobe_ip_table[hash_ptr((void *)ip, FPROBE_IP_HASH_BITS)]; -+ hlist_add_head_rcu(&node->hlist, head); - } - --static void fprobe_handler(unsigned long ip, unsigned long parent_ip, -- struct ftrace_ops *ops, struct ftrace_regs *fregs) -+/* Return true if there are synonims */ -+static bool delete_fprobe_node(struct fprobe_hlist_node *node) - { -- struct fprobe *fp; -- int bit; -+ lockdep_assert_held(&fprobe_mutex); - -- fp = container_of(ops, struct fprobe, ops); -- if (fprobe_disabled(fp)) -- return; -+ WRITE_ONCE(node->fp, NULL); -+ hlist_del_rcu(&node->hlist); -+ return !!find_first_fprobe_node(node->addr); -+} - -- /* recursion detection has to go before any traceable function and -- * all functions before this point should be marked as notrace -- */ -- bit = ftrace_test_recursion_trylock(ip, parent_ip); -- if (bit < 0) { -- fp->nmissed++; -- return; -+/* Check existence of the fprobe */ -+static bool is_fprobe_still_exist(struct fprobe *fp) -+{ -+ struct hlist_head *head; -+ struct fprobe_hlist *fph; -+ -+ head = &fprobe_table[hash_ptr(fp, FPROBE_HASH_BITS)]; -+ hlist_for_each_entry_rcu(fph, head, hlist, -+ lockdep_is_held(&fprobe_mutex)) { -+ if (fph->fp == fp) -+ return true; - } -- __fprobe_handler(ip, parent_ip, ops, fregs); -- ftrace_test_recursion_unlock(bit); -+ return false; -+} -+NOKPROBE_SYMBOL(is_fprobe_still_exist); -+ -+static int add_fprobe_hash(struct fprobe *fp) -+{ -+ struct fprobe_hlist *fph = fp->hlist_array; -+ struct hlist_head *head; -+ -+ lockdep_assert_held(&fprobe_mutex); -+ -+ if (WARN_ON_ONCE(!fph)) -+ return -EINVAL; -+ -+ if (is_fprobe_still_exist(fp)) -+ return -EEXIST; - -+ head = &fprobe_table[hash_ptr(fp, FPROBE_HASH_BITS)]; -+ hlist_add_head_rcu(&fp->hlist_array->hlist, head); -+ return 0; - } --NOKPROBE_SYMBOL(fprobe_handler); - --static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip, -- struct ftrace_ops *ops, struct ftrace_regs *fregs) -+static int del_fprobe_hash(struct fprobe *fp) - { -+ struct fprobe_hlist *fph = fp->hlist_array; -+ -+ lockdep_assert_held(&fprobe_mutex); -+ -+ if (WARN_ON_ONCE(!fph)) -+ return -EINVAL; -+ -+ if (!is_fprobe_still_exist(fp)) -+ return -ENOENT; -+ -+ fph->fp = NULL; -+ hlist_del_rcu(&fph->hlist); -+ return 0; -+} -+ -+/* Generic fprobe_header */ -+struct __fprobe_header { - struct fprobe *fp; -- int bit; -+ unsigned long size_words; -+} __packed; - -- fp = container_of(ops, struct fprobe, ops); -- if (fprobe_disabled(fp)) -- return; -+#define FPROBE_HEADER_SIZE_IN_LONG SIZE_IN_LONG(sizeof(struct __fprobe_header)) - -- /* recursion detection has to go before any traceable function and -- * all functions called before this point should be marked as notrace -- */ -- bit = ftrace_test_recursion_trylock(ip, parent_ip); -- if (bit < 0) { -- fp->nmissed++; -- return; -- } -+static inline bool write_fprobe_header(unsigned long *stack, -+ struct fprobe *fp, unsigned int size_words) -+{ -+ struct __fprobe_header *fph = (struct __fprobe_header *)stack; - -+ if (WARN_ON_ONCE(size_words > MAX_FPROBE_DATA_SIZE_WORD)) -+ return false; -+ -+ fph->fp = fp; -+ fph->size_words = size_words; -+ return true; -+} -+ -+static inline void read_fprobe_header(unsigned long *stack, -+ struct fprobe **fp, unsigned int *size_words) -+{ -+ struct __fprobe_header *fph = (struct __fprobe_header *)stack; -+ -+ *fp = fph->fp; -+ *size_words = fph->size_words; -+} -+ -+/* -+ * fprobe shadow stack management: -+ * Since fprobe shares a single fgraph_ops, it needs to share the stack entry -+ * among the probes on the same function exit. Note that a new probe can be -+ * registered before a target function is returning, we can not use the hash -+ * table to find the corresponding probes. Thus the probe address is stored on -+ * the shadow stack with its entry data size. -+ * -+ */ -+static inline int __fprobe_handler(unsigned long ip, unsigned long parent_ip, -+ struct fprobe *fp, struct ftrace_regs *fregs, -+ void *data) -+{ -+ if (!fp->entry_handler) -+ return 0; -+ -+ return fp->entry_handler(fp, ip, parent_ip, fregs, data); -+} -+ -+static inline int __fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip, -+ struct fprobe *fp, struct ftrace_regs *fregs, -+ void *data) -+{ -+ int ret; - /* - * This user handler is shared with other kprobes and is not expected to be - * called recursively. So if any other kprobe handler is running, this will -@@ -108,45 +205,183 @@ static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip, - */ - if (unlikely(kprobe_running())) { - fp->nmissed++; -- goto recursion_unlock; -+ return 0; - } - - kprobe_busy_begin(); -- __fprobe_handler(ip, parent_ip, ops, fregs); -+ ret = __fprobe_handler(ip, parent_ip, fp, fregs, data); - kprobe_busy_end(); -- --recursion_unlock: -- ftrace_test_recursion_unlock(bit); -+ return ret; - } - --static void fprobe_exit_handler(struct rethook_node *rh, void *data, -- unsigned long ret_ip, struct pt_regs *regs) -+static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, -+ struct ftrace_regs *fregs) - { -- struct fprobe *fp = (struct fprobe *)data; -- struct fprobe_rethook_node *fpr; -- struct ftrace_regs *fregs = (struct ftrace_regs *)regs; -- int bit; -+ struct fprobe_hlist_node *node, *first; -+ unsigned long *fgraph_data = NULL; -+ unsigned long func = trace->func; -+ unsigned long ret_ip; -+ int reserved_words; -+ struct fprobe *fp; -+ int used, ret; - -- if (!fp || fprobe_disabled(fp)) -- return; -+ if (WARN_ON_ONCE(!fregs)) -+ return 0; - -- fpr = container_of(rh, struct fprobe_rethook_node, node); -+ first = node = find_first_fprobe_node(func); -+ if (unlikely(!first)) -+ return 0; -+ -+ reserved_words = 0; -+ hlist_for_each_entry_from_rcu(node, hlist) { -+ if (node->addr != func) -+ break; -+ fp = READ_ONCE(node->fp); -+ if (!fp || !fp->exit_handler) -+ continue; -+ /* -+ * Since fprobe can be enabled until the next loop, we ignore the -+ * fprobe's disabled flag in this loop. -+ */ -+ reserved_words += -+ FPROBE_HEADER_SIZE_IN_LONG + SIZE_IN_LONG(fp->entry_data_size); -+ } -+ node = first; -+ if (reserved_words) { -+ fgraph_data = fgraph_reserve_data(gops->idx, reserved_words * sizeof(long)); -+ if (unlikely(!fgraph_data)) { -+ hlist_for_each_entry_from_rcu(node, hlist) { -+ if (node->addr != func) -+ break; -+ fp = READ_ONCE(node->fp); -+ if (fp && !fprobe_disabled(fp)) -+ fp->nmissed++; -+ } -+ return 0; -+ } -+ } - - /* -- * we need to assure no calls to traceable functions in-between the -- * end of fprobe_handler and the beginning of fprobe_exit_handler. -+ * TODO: recursion detection has been done in the fgraph. Thus we need -+ * to add a callback to increment missed counter. - */ -- bit = ftrace_test_recursion_trylock(fpr->entry_ip, fpr->entry_parent_ip); -- if (bit < 0) { -- fp->nmissed++; -+ ret_ip = ftrace_regs_get_return_address(fregs); -+ used = 0; -+ hlist_for_each_entry_from_rcu(node, hlist) { -+ int data_size; -+ void *data; -+ -+ if (node->addr != func) -+ break; -+ fp = READ_ONCE(node->fp); -+ if (!fp || fprobe_disabled(fp)) -+ continue; -+ -+ data_size = fp->entry_data_size; -+ if (data_size && fp->exit_handler) -+ data = fgraph_data + used + FPROBE_HEADER_SIZE_IN_LONG; -+ else -+ data = NULL; -+ -+ if (fprobe_shared_with_kprobes(fp)) -+ ret = __fprobe_kprobe_handler(func, ret_ip, fp, fregs, data); -+ else -+ ret = __fprobe_handler(func, ret_ip, fp, fregs, data); -+ -+ /* If entry_handler returns !0, nmissed is not counted but skips exit_handler. */ -+ if (!ret && fp->exit_handler) { -+ int size_words = SIZE_IN_LONG(data_size); -+ -+ if (write_fprobe_header(&fgraph_data[used], fp, size_words)) -+ used += FPROBE_HEADER_SIZE_IN_LONG + size_words; -+ } -+ } -+ if (used < reserved_words) -+ memset(fgraph_data + used, 0, reserved_words - used); -+ -+ /* If any exit_handler is set, data must be used. */ -+ return used != 0; -+} -+NOKPROBE_SYMBOL(fprobe_entry); -+ -+static void fprobe_return(struct ftrace_graph_ret *trace, -+ struct fgraph_ops *gops, -+ struct ftrace_regs *fregs) -+{ -+ unsigned long *fgraph_data = NULL; -+ unsigned long ret_ip; -+ struct fprobe *fp; -+ int size, curr; -+ int size_words; -+ -+ fgraph_data = (unsigned long *)fgraph_retrieve_data(gops->idx, &size); -+ if (WARN_ON_ONCE(!fgraph_data)) - return; -+ size_words = SIZE_IN_LONG(size); -+ ret_ip = ftrace_regs_get_instruction_pointer(fregs); -+ -+ preempt_disable(); -+ -+ curr = 0; -+ while (size_words > curr) { -+ read_fprobe_header(&fgraph_data[curr], &fp, &size); -+ if (!fp) -+ break; -+ curr += FPROBE_HEADER_SIZE_IN_LONG; -+ if (is_fprobe_still_exist(fp) && !fprobe_disabled(fp)) { -+ if (WARN_ON_ONCE(curr + size > size_words)) -+ break; -+ fp->exit_handler(fp, trace->func, ret_ip, fregs, -+ size ? fgraph_data + curr : NULL); -+ } -+ curr += size; - } -+ preempt_enable(); -+} -+NOKPROBE_SYMBOL(fprobe_return); -+ -+static struct fgraph_ops fprobe_graph_ops = { -+ .entryfunc = fprobe_entry, -+ .retfunc = fprobe_return, -+}; -+static int fprobe_graph_active; -+ -+/* Add @addrs to the ftrace filter and register fgraph if needed. */ -+static int fprobe_graph_add_ips(unsigned long *addrs, int num) -+{ -+ int ret; - -- fp->exit_handler(fp, fpr->entry_ip, ret_ip, fregs, -- fp->entry_data_size ? (void *)fpr->data : NULL); -- ftrace_test_recursion_unlock(bit); -+ lockdep_assert_held(&fprobe_mutex); -+ -+ ret = ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 0, 0); -+ if (ret) -+ return ret; -+ -+ if (!fprobe_graph_active) { -+ ret = register_ftrace_graph(&fprobe_graph_ops); -+ if (WARN_ON_ONCE(ret)) { -+ ftrace_free_filter(&fprobe_graph_ops.ops); -+ return ret; -+ } -+ } -+ fprobe_graph_active++; -+ return 0; -+} -+ -+/* Remove @addrs from the ftrace filter and unregister fgraph if possible. */ -+static void fprobe_graph_remove_ips(unsigned long *addrs, int num) -+{ -+ lockdep_assert_held(&fprobe_mutex); -+ -+ fprobe_graph_active--; -+ if (!fprobe_graph_active) { -+ /* Q: should we unregister it ? */ -+ unregister_ftrace_graph(&fprobe_graph_ops); -+ return; -+ } -+ -+ ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 1, 0); - } --NOKPROBE_SYMBOL(fprobe_exit_handler); - - static int symbols_cmp(const void *a, const void *b) - { -@@ -176,54 +411,97 @@ static unsigned long *get_ftrace_locations(const char **syms, int num) - return ERR_PTR(-ENOENT); - } - --static void fprobe_init(struct fprobe *fp) --{ -- fp->nmissed = 0; -- if (fprobe_shared_with_kprobes(fp)) -- fp->ops.func = fprobe_kprobe_handler; -- else -- fp->ops.func = fprobe_handler; -- -- fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS; --} -+struct filter_match_data { -+ const char *filter; -+ const char *notfilter; -+ size_t index; -+ size_t size; -+ unsigned long *addrs; -+}; - --static int fprobe_init_rethook(struct fprobe *fp, int num) -+static int filter_match_callback(void *data, const char *name, unsigned long addr) - { -- int size; -+ struct filter_match_data *match = data; - -- if (!fp->exit_handler) { -- fp->rethook = NULL; -+ if (!glob_match(match->filter, name) || -+ (match->notfilter && glob_match(match->notfilter, name))) - return 0; -- } - -- /* Initialize rethook if needed */ -- if (fp->nr_maxactive) -- num = fp->nr_maxactive; -- else -- num *= num_possible_cpus() * 2; -- if (num <= 0) -- return -EINVAL; -+ if (!ftrace_location(addr)) -+ return 0; - -- size = sizeof(struct fprobe_rethook_node) + fp->entry_data_size; -+ if (match->addrs) -+ match->addrs[match->index] = addr; - -- /* Initialize rethook */ -- fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler, size, num); -- if (IS_ERR(fp->rethook)) -- return PTR_ERR(fp->rethook); -+ match->index++; -+ return match->index == match->size; -+} - -- return 0; -+/* -+ * Make IP list from the filter/no-filter glob patterns. -+ * Return the number of matched symbols, or -ENOENT. -+ */ -+static int ip_list_from_filter(const char *filter, const char *notfilter, -+ unsigned long *addrs, size_t size) -+{ -+ struct filter_match_data match = { .filter = filter, .notfilter = notfilter, -+ .index = 0, .size = size, .addrs = addrs}; -+ int ret; -+ -+ ret = kallsyms_on_each_symbol(filter_match_callback, &match); -+ if (ret < 0) -+ return ret; -+ ret = module_kallsyms_on_each_symbol(NULL, filter_match_callback, &match); -+ if (ret < 0) -+ return ret; -+ -+ return match.index ?: -ENOENT; - } - - static void fprobe_fail_cleanup(struct fprobe *fp) - { -- if (!IS_ERR_OR_NULL(fp->rethook)) { -- /* Don't need to cleanup rethook->handler because this is not used. */ -- rethook_free(fp->rethook); -- fp->rethook = NULL; -+ kfree(fp->hlist_array); -+ fp->hlist_array = NULL; -+} -+ -+/* Initialize the fprobe data structure. */ -+static int fprobe_init(struct fprobe *fp, unsigned long *addrs, int num) -+{ -+ struct fprobe_hlist *hlist_array; -+ unsigned long addr; -+ int size, i; -+ -+ if (!fp || !addrs || num <= 0) -+ return -EINVAL; -+ -+ size = ALIGN(fp->entry_data_size, sizeof(long)); -+ if (size > MAX_FPROBE_DATA_SIZE) -+ return -E2BIG; -+ fp->entry_data_size = size; -+ -+ hlist_array = kzalloc(struct_size(hlist_array, array, num), GFP_KERNEL); -+ if (!hlist_array) -+ return -ENOMEM; -+ -+ fp->nmissed = 0; -+ -+ hlist_array->size = num; -+ fp->hlist_array = hlist_array; -+ hlist_array->fp = fp; -+ for (i = 0; i < num; i++) { -+ hlist_array->array[i].fp = fp; -+ addr = ftrace_location(addrs[i]); -+ if (!addr) { -+ fprobe_fail_cleanup(fp); -+ return -ENOENT; -+ } -+ hlist_array->array[i].addr = addr; - } -- ftrace_free_filter(&fp->ops); -+ return 0; - } - -+#define FPROBE_IPS_MAX INT_MAX -+ - /** - * register_fprobe() - Register fprobe to ftrace by pattern. - * @fp: A fprobe data structure to be registered. -@@ -237,46 +515,24 @@ static void fprobe_fail_cleanup(struct fprobe *fp) - */ - int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter) - { -- struct ftrace_hash *hash; -- unsigned char *str; -- int ret, len; -+ unsigned long *addrs; -+ int ret; - - if (!fp || !filter) - return -EINVAL; - -- fprobe_init(fp); -- -- len = strlen(filter); -- str = kstrdup(filter, GFP_KERNEL); -- ret = ftrace_set_filter(&fp->ops, str, len, 0); -- kfree(str); -- if (ret) -+ ret = ip_list_from_filter(filter, notfilter, NULL, FPROBE_IPS_MAX); -+ if (ret < 0) - return ret; - -- if (notfilter) { -- len = strlen(notfilter); -- str = kstrdup(notfilter, GFP_KERNEL); -- ret = ftrace_set_notrace(&fp->ops, str, len, 0); -- kfree(str); -- if (ret) -- goto out; -- } -- -- /* TODO: -- * correctly calculate the total number of filtered symbols -- * from both filter and notfilter. -- */ -- hash = rcu_access_pointer(fp->ops.local_hash.filter_hash); -- if (WARN_ON_ONCE(!hash)) -- goto out; -- -- ret = fprobe_init_rethook(fp, (int)hash->count); -- if (!ret) -- ret = register_ftrace_function(&fp->ops); -+ addrs = kcalloc(ret, sizeof(unsigned long), GFP_KERNEL); -+ if (!addrs) -+ return -ENOMEM; -+ ret = ip_list_from_filter(filter, notfilter, addrs, ret); -+ if (ret > 0) -+ ret = register_fprobe_ips(fp, addrs, ret); - --out: -- if (ret) -- fprobe_fail_cleanup(fp); -+ kfree(addrs); - return ret; - } - EXPORT_SYMBOL_GPL(register_fprobe); -@@ -284,7 +540,7 @@ EXPORT_SYMBOL_GPL(register_fprobe); - /** - * register_fprobe_ips() - Register fprobe to ftrace by address. - * @fp: A fprobe data structure to be registered. -- * @addrs: An array of target ftrace location addresses. -+ * @addrs: An array of target function address. - * @num: The number of entries of @addrs. - * - * Register @fp to ftrace for enabling the probe on the address given by @addrs. -@@ -296,23 +552,27 @@ EXPORT_SYMBOL_GPL(register_fprobe); - */ - int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num) - { -- int ret; -- -- if (!fp || !addrs || num <= 0) -- return -EINVAL; -+ struct fprobe_hlist *hlist_array; -+ int ret, i; - -- fprobe_init(fp); -- -- ret = ftrace_set_filter_ips(&fp->ops, addrs, num, 0, 0); -+ ret = fprobe_init(fp, addrs, num); - if (ret) - return ret; - -- ret = fprobe_init_rethook(fp, num); -- if (!ret) -- ret = register_ftrace_function(&fp->ops); -+ mutex_lock(&fprobe_mutex); -+ -+ hlist_array = fp->hlist_array; -+ ret = fprobe_graph_add_ips(addrs, num); -+ if (!ret) { -+ add_fprobe_hash(fp); -+ for (i = 0; i < hlist_array->size; i++) -+ insert_fprobe_node(&hlist_array->array[i]); -+ } -+ mutex_unlock(&fprobe_mutex); - - if (ret) - fprobe_fail_cleanup(fp); -+ - return ret; - } - EXPORT_SYMBOL_GPL(register_fprobe_ips); -@@ -350,14 +610,13 @@ EXPORT_SYMBOL_GPL(register_fprobe_syms); - - bool fprobe_is_registered(struct fprobe *fp) - { -- if (!fp || (fp->ops.saved_func != fprobe_handler && -- fp->ops.saved_func != fprobe_kprobe_handler)) -+ if (!fp || !fp->hlist_array) - return false; - return true; - } - - /** -- * unregister_fprobe() - Unregister fprobe from ftrace -+ * unregister_fprobe() - Unregister fprobe. - * @fp: A fprobe data structure to be unregistered. - * - * Unregister fprobe (and remove ftrace hooks from the function entries). -@@ -366,23 +625,41 @@ bool fprobe_is_registered(struct fprobe *fp) - */ - int unregister_fprobe(struct fprobe *fp) - { -- int ret; -+ struct fprobe_hlist *hlist_array; -+ unsigned long *addrs = NULL; -+ int ret = 0, i, count; - -- if (!fprobe_is_registered(fp)) -- return -EINVAL; -+ mutex_lock(&fprobe_mutex); -+ if (!fp || !is_fprobe_still_exist(fp)) { -+ ret = -EINVAL; -+ goto out; -+ } - -- if (!IS_ERR_OR_NULL(fp->rethook)) -- rethook_stop(fp->rethook); -+ hlist_array = fp->hlist_array; -+ addrs = kcalloc(hlist_array->size, sizeof(unsigned long), GFP_KERNEL); -+ if (!addrs) { -+ ret = -ENOMEM; /* TODO: Fallback to one-by-one loop */ -+ goto out; -+ } - -- ret = unregister_ftrace_function(&fp->ops); -- if (ret < 0) -- return ret; -+ /* Remove non-synonim ips from table and hash */ -+ count = 0; -+ for (i = 0; i < hlist_array->size; i++) { -+ if (!delete_fprobe_node(&hlist_array->array[i])) -+ addrs[count++] = hlist_array->array[i].addr; -+ } -+ del_fprobe_hash(fp); - -- if (!IS_ERR_OR_NULL(fp->rethook)) -- rethook_free(fp->rethook); -+ if (count) -+ fprobe_graph_remove_ips(addrs, count); - -- ftrace_free_filter(&fp->ops); -+ kfree_rcu(hlist_array, rcu); -+ fp->hlist_array = NULL; - -+out: -+ mutex_unlock(&fprobe_mutex); -+ -+ kfree(addrs); - return ret; - } - EXPORT_SYMBOL_GPL(unregister_fprobe); -diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c -index 271ce0caeec03..cf92111b5c79d 100644 ---- a/lib/test_fprobe.c -+++ b/lib/test_fprobe.c -@@ -17,10 +17,8 @@ static u32 rand1, entry_val, exit_val; - /* Use indirect calls to avoid inlining the target functions */ - static u32 (*target)(u32 value); - static u32 (*target2)(u32 value); --static u32 (*target_nest)(u32 value, u32 (*nest)(u32)); - static unsigned long target_ip; - static unsigned long target2_ip; --static unsigned long target_nest_ip; - static int entry_return_value; - - static noinline u32 fprobe_selftest_target(u32 value) -@@ -33,11 +31,6 @@ static noinline u32 fprobe_selftest_target2(u32 value) - return (value / div_factor) + 1; - } - --static noinline u32 fprobe_selftest_nest_target(u32 value, u32 (*nest)(u32)) --{ -- return nest(value + 2); --} -- - static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip, - unsigned long ret_ip, - struct ftrace_regs *fregs, void *data) -@@ -79,22 +72,6 @@ static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, - KUNIT_EXPECT_NULL(current_test, data); - } - --static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip, -- unsigned long ret_ip, -- struct ftrace_regs *fregs, void *data) --{ -- KUNIT_EXPECT_FALSE(current_test, preemptible()); -- return 0; --} -- --static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip, -- unsigned long ret_ip, -- struct ftrace_regs *fregs, void *data) --{ -- KUNIT_EXPECT_FALSE(current_test, preemptible()); -- KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip); --} -- - /* Test entry only (no rethook) */ - static void test_fprobe_entry(struct kunit *test) - { -@@ -191,25 +168,6 @@ static void test_fprobe_data(struct kunit *test) - KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); - } - --/* Test nr_maxactive */ --static void test_fprobe_nest(struct kunit *test) --{ -- static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_nest_target"}; -- struct fprobe fp = { -- .entry_handler = nest_entry_handler, -- .exit_handler = nest_exit_handler, -- .nr_maxactive = 1, -- }; -- -- current_test = test; -- KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2)); -- -- target_nest(rand1, target); -- KUNIT_EXPECT_EQ(test, 1, fp.nmissed); -- -- KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp)); --} -- - static void test_fprobe_skip(struct kunit *test) - { - struct fprobe fp = { -@@ -247,10 +205,8 @@ static int fprobe_test_init(struct kunit *test) - rand1 = get_random_u32_above(div_factor); - target = fprobe_selftest_target; - target2 = fprobe_selftest_target2; -- target_nest = fprobe_selftest_nest_target; - target_ip = get_ftrace_location(target); - target2_ip = get_ftrace_location(target2); -- target_nest_ip = get_ftrace_location(target_nest); - - return 0; - } -@@ -260,7 +216,6 @@ static struct kunit_case fprobe_testcases[] = { - KUNIT_CASE(test_fprobe), - KUNIT_CASE(test_fprobe_syms), - KUNIT_CASE(test_fprobe_data), -- KUNIT_CASE(test_fprobe_nest), - KUNIT_CASE(test_fprobe_skip), - {} - }; --- -2.39.5 - diff --git a/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch b/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch deleted file mode 100644 index 0c7d70ec21..0000000000 --- a/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch +++ /dev/null @@ -1,207 +0,0 @@ -From 96eedf4d4d07660c69478c2a7c41d8ceee750de6 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 26 Dec 2024 14:12:20 +0900 -Subject: fprobe: Use ftrace_regs in fprobe entry handler - -From: Masami Hiramatsu (Google) - -[ Upstream commit 46bc082388560a95e3649b698a4675e5ea3262e6 ] - -This allows fprobes to be available with CONFIG_DYNAMIC_FTRACE_WITH_ARGS -instead of CONFIG_DYNAMIC_FTRACE_WITH_REGS, then we can enable fprobe -on arm64. - -Cc: Alexei Starovoitov -Cc: Martin KaFai Lau -Cc: bpf -Cc: Alexei Starovoitov -Cc: Jiri Olsa -Cc: Alan Maguire -Cc: Mark Rutland -Link: https://lore.kernel.org/173518994037.391279.2786805566359674586.stgit@devnote2 -Signed-off-by: Masami Hiramatsu (Google) -Acked-by: Florent Revest -Signed-off-by: Steven Rostedt (Google) -Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args") -Signed-off-by: Sasha Levin ---- - include/linux/fprobe.h | 2 +- - kernel/trace/Kconfig | 3 ++- - kernel/trace/bpf_trace.c | 10 +++++++--- - kernel/trace/fprobe.c | 3 ++- - kernel/trace/trace_fprobe.c | 11 ++++++++--- - lib/test_fprobe.c | 4 ++-- - samples/fprobe/fprobe_example.c | 2 +- - 7 files changed, 23 insertions(+), 12 deletions(-) - -diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h -index f398695881175..ca64ee5e45d2c 100644 ---- a/include/linux/fprobe.h -+++ b/include/linux/fprobe.h -@@ -10,7 +10,7 @@ - struct fprobe; - - typedef int (*fprobe_entry_cb)(struct fprobe *fp, unsigned long entry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *regs, - void *entry_data); - - typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip, -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index c5ab2a561272d..f10ca86fbfad2 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -297,7 +297,7 @@ config DYNAMIC_FTRACE_WITH_ARGS - config FPROBE - bool "Kernel Function Probe (fprobe)" - depends on FUNCTION_TRACER -- depends on DYNAMIC_FTRACE_WITH_REGS -+ depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS - depends on HAVE_RETHOOK - select RETHOOK - default n -@@ -682,6 +682,7 @@ config FPROBE_EVENTS - select TRACING - select PROBE_EVENTS - select DYNAMIC_EVENTS -+ depends on DYNAMIC_FTRACE_WITH_REGS - default y - help - This allows user to add tracing events on the function entry and -diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c -index 2c2205e91fee9..6b58e84995e46 100644 ---- a/kernel/trace/bpf_trace.c -+++ b/kernel/trace/bpf_trace.c -@@ -2562,7 +2562,7 @@ struct bpf_session_run_ctx { - void *data; - }; - --#ifdef CONFIG_FPROBE -+#if defined(CONFIG_FPROBE) && defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS) - struct bpf_kprobe_multi_link { - struct bpf_link link; - struct fprobe fp; -@@ -2814,12 +2814,16 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, - - static int - kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *fregs, - void *data) - { -+ struct pt_regs *regs = ftrace_get_regs(fregs); - struct bpf_kprobe_multi_link *link; - int err; - -+ if (!regs) -+ return 0; -+ - link = container_of(fp, struct bpf_kprobe_multi_link, fp); - err = kprobe_multi_link_prog_run(link, get_entry_ip(fentry_ip), regs, false, data); - return is_kprobe_session(link->link.prog) ? err : 0; -@@ -3094,7 +3098,7 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr - kvfree(cookies); - return err; - } --#else /* !CONFIG_FPROBE */ -+#else /* !CONFIG_FPROBE || !CONFIG_DYNAMIC_FTRACE_WITH_REGS */ - int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) - { - return -EOPNOTSUPP; -diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c -index 9ff0182458408..3d37892838739 100644 ---- a/kernel/trace/fprobe.c -+++ b/kernel/trace/fprobe.c -@@ -46,7 +46,7 @@ static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip, - } - - if (fp->entry_handler) -- ret = fp->entry_handler(fp, ip, parent_ip, ftrace_get_regs(fregs), entry_data); -+ ret = fp->entry_handler(fp, ip, parent_ip, fregs, entry_data); - - /* If entry_handler returns !0, nmissed is not counted. */ - if (rh) { -@@ -182,6 +182,7 @@ static void fprobe_init(struct fprobe *fp) - fp->ops.func = fprobe_kprobe_handler; - else - fp->ops.func = fprobe_handler; -+ - fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS; - } - -diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c -index 99048c3303822..c1eef70212b25 100644 ---- a/kernel/trace/trace_fprobe.c -+++ b/kernel/trace/trace_fprobe.c -@@ -217,12 +217,13 @@ NOKPROBE_SYMBOL(fentry_trace_func); - - /* function exit handler */ - static int trace_fprobe_entry_handler(struct fprobe *fp, unsigned long entry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *fregs, - void *entry_data) - { - struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp); -+ struct pt_regs *regs = ftrace_get_regs(fregs); - -- if (tf->tp.entry_arg) -+ if (regs && tf->tp.entry_arg) - store_trace_entry_data(entry_data, &tf->tp, regs); - - return 0; -@@ -339,12 +340,16 @@ NOKPROBE_SYMBOL(fexit_perf_func); - #endif /* CONFIG_PERF_EVENTS */ - - static int fentry_dispatcher(struct fprobe *fp, unsigned long entry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *fregs, - void *entry_data) - { - struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp); -+ struct pt_regs *regs = ftrace_get_regs(fregs); - int ret = 0; - -+ if (!regs) -+ return 0; -+ - if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE)) - fentry_trace_func(tf, entry_ip, regs); - #ifdef CONFIG_PERF_EVENTS -diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c -index 24de0e5ff8599..ff607babba189 100644 ---- a/lib/test_fprobe.c -+++ b/lib/test_fprobe.c -@@ -40,7 +40,7 @@ static noinline u32 fprobe_selftest_nest_target(u32 value, u32 (*nest)(u32)) - - static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip, - unsigned long ret_ip, -- struct pt_regs *regs, void *data) -+ struct ftrace_regs *fregs, void *data) - { - KUNIT_EXPECT_FALSE(current_test, preemptible()); - /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */ -@@ -81,7 +81,7 @@ static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, - - static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip, - unsigned long ret_ip, -- struct pt_regs *regs, void *data) -+ struct ftrace_regs *fregs, void *data) - { - KUNIT_EXPECT_FALSE(current_test, preemptible()); - return 0; -diff --git a/samples/fprobe/fprobe_example.c b/samples/fprobe/fprobe_example.c -index 0a50b05add969..c234afae52d6f 100644 ---- a/samples/fprobe/fprobe_example.c -+++ b/samples/fprobe/fprobe_example.c -@@ -50,7 +50,7 @@ static void show_backtrace(void) - - static int sample_entry_handler(struct fprobe *fp, unsigned long ip, - unsigned long ret_ip, -- struct pt_regs *regs, void *data) -+ struct ftrace_regs *fregs, void *data) - { - if (use_trace) - /* --- -2.39.5 - diff --git a/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch b/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch deleted file mode 100644 index 5e3632eacd..0000000000 --- a/queue-6.13/fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch +++ /dev/null @@ -1,261 +0,0 @@ -From 9ec816522c378200971176807181e023885863af Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 26 Dec 2024 14:12:31 +0900 -Subject: fprobe: Use ftrace_regs in fprobe exit handler - -From: Masami Hiramatsu (Google) - -[ Upstream commit 762abbc0d09f7ae123c82d315eb1a961c1a2cf7b ] - -Change the fprobe exit handler to use ftrace_regs structure instead of -pt_regs. This also introduce HAVE_FTRACE_REGS_HAVING_PT_REGS which -means the ftrace_regs is including the pt_regs so that ftrace_regs -can provide pt_regs without memory allocation. -Fprobe introduces a new dependency with that. - -Signed-off-by: Masami Hiramatsu (Google) -Acked-by: Heiko Carstens # s390 -Cc: Huacai Chen -Cc: Alexei Starovoitov -Cc: Florent Revest -Cc: bpf -Cc: Alan Maguire -Cc: Heiko Carstens -Cc: WANG Xuerui -Cc: Vasily Gorbik -Cc: Alexander Gordeev -Cc: Christian Borntraeger -Cc: Sven Schnelle -Cc: Thomas Gleixner -Cc: Ingo Molnar -Cc: Borislav Petkov -Cc: Dave Hansen -Cc: x86@kernel.org -Cc: "H. Peter Anvin" -Cc: Mark Rutland -Cc: Mathieu Desnoyers -Cc: Song Liu -Cc: Jiri Olsa -Cc: KP Singh -Cc: Matt Bobrowski -Cc: Alexei Starovoitov -Cc: Daniel Borkmann -Cc: Andrii Nakryiko -Cc: Martin KaFai Lau -Cc: Eduard Zingerman -Cc: Yonghong Song -Cc: John Fastabend -Cc: Stanislav Fomichev -Cc: Hao Luo -Cc: Andrew Morton -Link: https://lore.kernel.org/173518995092.391279.6765116450352977627.stgit@devnote2 -Signed-off-by: Steven Rostedt (Google) -Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args") -Signed-off-by: Sasha Levin ---- - arch/loongarch/Kconfig | 1 + - arch/s390/Kconfig | 1 + - arch/x86/Kconfig | 1 + - include/linux/fprobe.h | 2 +- - include/linux/ftrace.h | 6 ++++++ - kernel/trace/Kconfig | 7 +++++++ - kernel/trace/bpf_trace.c | 6 +++++- - kernel/trace/fprobe.c | 3 ++- - kernel/trace/trace_fprobe.c | 6 +++++- - lib/test_fprobe.c | 6 +++--- - samples/fprobe/fprobe_example.c | 2 +- - 11 files changed, 33 insertions(+), 8 deletions(-) - -diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig -index 49f5bfc00e5a1..6396615ec035e 100644 ---- a/arch/loongarch/Kconfig -+++ b/arch/loongarch/Kconfig -@@ -128,6 +128,7 @@ config LOONGARCH - select HAVE_DMA_CONTIGUOUS - select HAVE_DYNAMIC_FTRACE - select HAVE_DYNAMIC_FTRACE_WITH_ARGS -+ select HAVE_FTRACE_REGS_HAVING_PT_REGS - select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - select HAVE_DYNAMIC_FTRACE_WITH_REGS - select HAVE_EBPF_JIT -diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig -index a8cecae74fe81..c7a7f91a6ce19 100644 ---- a/arch/s390/Kconfig -+++ b/arch/s390/Kconfig -@@ -184,6 +184,7 @@ config S390 - select HAVE_DMA_CONTIGUOUS - select HAVE_DYNAMIC_FTRACE - select HAVE_DYNAMIC_FTRACE_WITH_ARGS -+ select HAVE_FTRACE_REGS_HAVING_PT_REGS - select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - select HAVE_DYNAMIC_FTRACE_WITH_REGS - select HAVE_EBPF_JIT if HAVE_MARCH_Z196_FEATURES -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index aa317f6064b89..9b20a96651671 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -224,6 +224,7 @@ config X86 - select HAVE_DYNAMIC_FTRACE - select HAVE_DYNAMIC_FTRACE_WITH_REGS - select HAVE_DYNAMIC_FTRACE_WITH_ARGS if X86_64 -+ select HAVE_FTRACE_REGS_HAVING_PT_REGS if X86_64 - select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - select HAVE_SAMPLE_FTRACE_DIRECT if X86_64 - select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if X86_64 -diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h -index ca64ee5e45d2c..ef609bcca0f92 100644 ---- a/include/linux/fprobe.h -+++ b/include/linux/fprobe.h -@@ -14,7 +14,7 @@ typedef int (*fprobe_entry_cb)(struct fprobe *fp, unsigned long entry_ip, - void *entry_data); - - typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *regs, - void *entry_data); - - /** -diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h -index b7407004c799e..46ac44366c90a 100644 ---- a/include/linux/ftrace.h -+++ b/include/linux/ftrace.h -@@ -176,6 +176,12 @@ static inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) - #define ftrace_regs_set_instruction_pointer(fregs, ip) do { } while (0) - #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */ - -+#ifdef CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS -+ -+static_assert(sizeof(struct pt_regs) == ftrace_regs_size()); -+ -+#endif /* CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */ -+ - static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs) - { - if (!fregs) -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index f10ca86fbfad2..7f8165f2049a5 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -57,6 +57,12 @@ config HAVE_DYNAMIC_FTRACE_WITH_ARGS - This allows for use of ftrace_regs_get_argument() and - ftrace_regs_get_stack_pointer(). - -+config HAVE_FTRACE_REGS_HAVING_PT_REGS -+ bool -+ help -+ If this is set, ftrace_regs has pt_regs, thus it can convert to -+ pt_regs without allocating memory. -+ - config HAVE_DYNAMIC_FTRACE_NO_PATCHABLE - bool - help -@@ -298,6 +304,7 @@ config FPROBE - bool "Kernel Function Probe (fprobe)" - depends on FUNCTION_TRACER - depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS -+ depends on HAVE_FTRACE_REGS_HAVING_PT_REGS || !HAVE_DYNAMIC_FTRACE_WITH_ARGS - depends on HAVE_RETHOOK - select RETHOOK - default n -diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c -index 6b58e84995e46..968520b04b6d3 100644 ---- a/kernel/trace/bpf_trace.c -+++ b/kernel/trace/bpf_trace.c -@@ -2831,10 +2831,14 @@ kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip, - - static void - kprobe_multi_link_exit_handler(struct fprobe *fp, unsigned long fentry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *fregs, - void *data) - { - struct bpf_kprobe_multi_link *link; -+ struct pt_regs *regs = ftrace_get_regs(fregs); -+ -+ if (!regs) -+ return; - - link = container_of(fp, struct bpf_kprobe_multi_link, fp); - kprobe_multi_link_prog_run(link, get_entry_ip(fentry_ip), regs, true, data); -diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c -index 3d37892838739..90a3c8e2bbdf1 100644 ---- a/kernel/trace/fprobe.c -+++ b/kernel/trace/fprobe.c -@@ -124,6 +124,7 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data, - { - struct fprobe *fp = (struct fprobe *)data; - struct fprobe_rethook_node *fpr; -+ struct ftrace_regs *fregs = (struct ftrace_regs *)regs; - int bit; - - if (!fp || fprobe_disabled(fp)) -@@ -141,7 +142,7 @@ static void fprobe_exit_handler(struct rethook_node *rh, void *data, - return; - } - -- fp->exit_handler(fp, fpr->entry_ip, ret_ip, regs, -+ fp->exit_handler(fp, fpr->entry_ip, ret_ip, fregs, - fp->entry_data_size ? (void *)fpr->data : NULL); - ftrace_test_recursion_unlock(bit); - } -diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c -index c1eef70212b25..d906baba2d40c 100644 ---- a/kernel/trace/trace_fprobe.c -+++ b/kernel/trace/trace_fprobe.c -@@ -361,10 +361,14 @@ static int fentry_dispatcher(struct fprobe *fp, unsigned long entry_ip, - NOKPROBE_SYMBOL(fentry_dispatcher); - - static void fexit_dispatcher(struct fprobe *fp, unsigned long entry_ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *fregs, - void *entry_data) - { - struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp); -+ struct pt_regs *regs = ftrace_get_regs(fregs); -+ -+ if (!regs) -+ return; - - if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE)) - fexit_trace_func(tf, entry_ip, ret_ip, regs, entry_data); -diff --git a/lib/test_fprobe.c b/lib/test_fprobe.c -index ff607babba189..271ce0caeec03 100644 ---- a/lib/test_fprobe.c -+++ b/lib/test_fprobe.c -@@ -59,9 +59,9 @@ static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip, - - static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, - unsigned long ret_ip, -- struct pt_regs *regs, void *data) -+ struct ftrace_regs *fregs, void *data) - { -- unsigned long ret = regs_return_value(regs); -+ unsigned long ret = ftrace_regs_get_return_value(fregs); - - KUNIT_EXPECT_FALSE(current_test, preemptible()); - if (ip != target_ip) { -@@ -89,7 +89,7 @@ static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip, - - static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip, - unsigned long ret_ip, -- struct pt_regs *regs, void *data) -+ struct ftrace_regs *fregs, void *data) - { - KUNIT_EXPECT_FALSE(current_test, preemptible()); - KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip); -diff --git a/samples/fprobe/fprobe_example.c b/samples/fprobe/fprobe_example.c -index c234afae52d6f..bfe98ce826f3a 100644 ---- a/samples/fprobe/fprobe_example.c -+++ b/samples/fprobe/fprobe_example.c -@@ -67,7 +67,7 @@ static int sample_entry_handler(struct fprobe *fp, unsigned long ip, - } - - static void sample_exit_handler(struct fprobe *fp, unsigned long ip, -- unsigned long ret_ip, struct pt_regs *regs, -+ unsigned long ret_ip, struct ftrace_regs *regs, - void *data) - { - unsigned long rip = ret_ip; --- -2.39.5 - diff --git a/queue-6.13/series b/queue-6.13/series index f8a1d21ec4..47b48d517b 100644 --- a/queue-6.13/series +++ b/queue-6.13/series @@ -94,13 +94,6 @@ nvme-ioctl-fix-leaked-requests-on-mapping-error.patch wifi-mac80211-support-parsing-epcs-ml-element.patch wifi-mac80211-fix-mle-non-inheritance-parsing.patch wifi-mac80211-fix-vendor-specific-inheritance.patch -fgraph-replace-fgraph_ret_regs-with-ftrace_regs.patch -fprobe-use-ftrace_regs-in-fprobe-entry-handler.patch -fprobe-use-ftrace_regs-in-fprobe-exit-handler.patch -tracing-add-ftrace_partial_regs-for-converting-ftrac.patch -tracing-add-ftrace_fill_perf_regs-for-perf-event.patch -fprobe-rewrite-fprobe-on-function-graph-tracer.patch -tracing-fprobe-events-log-error-for-exceeding-the-nu.patch drm-nouveau-select-fw-caching.patch bluetooth-btusb-initialize-.owner-field-of-force_pol.patch nvmet-remove-old-function-prototype.patch diff --git a/queue-6.13/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch b/queue-6.13/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch deleted file mode 100644 index 1921c3190b..0000000000 --- a/queue-6.13/tracing-add-ftrace_fill_perf_regs-for-perf-event.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 2dc177cc7af51eb92a7f8ee3b81edfcc1601d361 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 26 Dec 2024 14:12:59 +0900 -Subject: tracing: Add ftrace_fill_perf_regs() for perf event - -From: Masami Hiramatsu (Google) - -[ Upstream commit d5d01b71996ec03af51b3c0736c92d0fc89703b5 ] - -Add ftrace_fill_perf_regs() which should be compatible with the -perf_fetch_caller_regs(). In other words, the pt_regs returned from the -ftrace_fill_perf_regs() must satisfy 'user_mode(regs) == false' and can be -used for stack tracing. - -Signed-off-by: Masami Hiramatsu (Google) -Acked-by: Will Deacon -Acked-by: Heiko Carstens # s390 -Cc: Alexei Starovoitov -Cc: Florent Revest -Cc: Martin KaFai Lau -Cc: bpf -Cc: Alexei Starovoitov -Cc: Jiri Olsa -Cc: Alan Maguire -Cc: Heiko Carstens -Cc: Mark Rutland -Cc: Catalin Marinas -Cc: Will Deacon -Cc: Michael Ellerman -Cc: Nicholas Piggin -Cc: Christophe Leroy -Cc: Naveen N Rao -Cc: Madhavan Srinivasan -Cc: Vasily Gorbik -Cc: Alexander Gordeev -Cc: Christian Borntraeger -Cc: Sven Schnelle -Cc: Thomas Gleixner -Cc: Ingo Molnar -Cc: Borislav Petkov -Cc: Dave Hansen -Cc: x86@kernel.org -Cc: "H. Peter Anvin" -Link: https://lore.kernel.org/173518997908.391279.15910334347345106424.stgit@devnote2 -Signed-off-by: Steven Rostedt (Google) -Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args") -Signed-off-by: Sasha Levin ---- - arch/arm64/include/asm/ftrace.h | 7 +++++++ - arch/powerpc/include/asm/ftrace.h | 7 +++++++ - arch/s390/include/asm/ftrace.h | 6 ++++++ - arch/x86/include/asm/ftrace.h | 7 +++++++ - include/linux/ftrace.h | 31 +++++++++++++++++++++++++++++++ - 5 files changed, 58 insertions(+) - -diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h -index 09210f853f12d..10e56522122aa 100644 ---- a/arch/arm64/include/asm/ftrace.h -+++ b/arch/arm64/include/asm/ftrace.h -@@ -148,6 +148,13 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) - return regs; - } - -+#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ -+ (_regs)->pc = arch_ftrace_regs(fregs)->pc; \ -+ (_regs)->regs[29] = arch_ftrace_regs(fregs)->fp; \ -+ (_regs)->sp = arch_ftrace_regs(fregs)->sp; \ -+ (_regs)->pstate = PSR_MODE_EL1h; \ -+ } while (0) -+ - int ftrace_regs_query_register_offset(const char *name); - - int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); -diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h -index db481b336bca4..fe181bafdca4f 100644 ---- a/arch/powerpc/include/asm/ftrace.h -+++ b/arch/powerpc/include/asm/ftrace.h -@@ -43,6 +43,13 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs * - return arch_ftrace_regs(fregs)->regs.msr ? &arch_ftrace_regs(fregs)->regs : NULL; - } - -+#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ -+ (_regs)->result = 0; \ -+ (_regs)->nip = arch_ftrace_regs(fregs)->regs.nip; \ -+ (_regs)->gpr[1] = arch_ftrace_regs(fregs)->regs.gpr[1]; \ -+ asm volatile("mfmsr %0" : "=r" ((_regs)->msr)); \ -+ } while (0) -+ - static __always_inline void - ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, - unsigned long ip) -diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h -index 5c94c1fc1bc1c..5b7cb49c41ee0 100644 ---- a/arch/s390/include/asm/ftrace.h -+++ b/arch/s390/include/asm/ftrace.h -@@ -76,6 +76,12 @@ ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs) - return ftrace_regs_get_stack_pointer(fregs); - } - -+#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ -+ (_regs)->psw.mask = 0; \ -+ (_regs)->psw.addr = arch_ftrace_regs(fregs)->regs.psw.addr; \ -+ (_regs)->gprs[15] = arch_ftrace_regs(fregs)->regs.gprs[15]; \ -+ } while (0) -+ - #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - /* - * When an ftrace registered caller is tracing a function that is -diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h -index d61407c680c28..7e06f8c7937aa 100644 ---- a/arch/x86/include/asm/ftrace.h -+++ b/arch/x86/include/asm/ftrace.h -@@ -47,6 +47,13 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) - return &arch_ftrace_regs(fregs)->regs; - } - -+#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \ -+ (_regs)->ip = arch_ftrace_regs(fregs)->regs.ip; \ -+ (_regs)->sp = arch_ftrace_regs(fregs)->regs.sp; \ -+ (_regs)->cs = __KERNEL_CS; \ -+ (_regs)->flags = 0; \ -+ } while (0) -+ - #define ftrace_regs_set_instruction_pointer(fregs, _ip) \ - do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) - -diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h -index 863c014dff683..56cb3d243c6c4 100644 ---- a/include/linux/ftrace.h -+++ b/include/linux/ftrace.h -@@ -207,6 +207,37 @@ ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs) - - #endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */ - -+#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS -+ -+/* -+ * Please define arch dependent pt_regs which compatible to the -+ * perf_arch_fetch_caller_regs() but based on ftrace_regs. -+ * This requires -+ * - user_mode(_regs) returns false (always kernel mode). -+ * - able to use the _regs for stack trace. -+ */ -+#ifndef arch_ftrace_fill_perf_regs -+/* As same as perf_arch_fetch_caller_regs(), do nothing by default */ -+#define arch_ftrace_fill_perf_regs(fregs, _regs) do {} while (0) -+#endif -+ -+static __always_inline struct pt_regs * -+ftrace_fill_perf_regs(struct ftrace_regs *fregs, struct pt_regs *regs) -+{ -+ arch_ftrace_fill_perf_regs(fregs, regs); -+ return regs; -+} -+ -+#else /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */ -+ -+static __always_inline struct pt_regs * -+ftrace_fill_perf_regs(struct ftrace_regs *fregs, struct pt_regs *regs) -+{ -+ return &arch_ftrace_regs(fregs)->regs; -+} -+ -+#endif -+ - /* - * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs. - * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs. --- -2.39.5 - diff --git a/queue-6.13/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch b/queue-6.13/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch deleted file mode 100644 index 418f517689..0000000000 --- a/queue-6.13/tracing-add-ftrace_partial_regs-for-converting-ftrac.patch +++ /dev/null @@ -1,124 +0,0 @@ -From d610ad390f261355db36806d148174e492d32f0c Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 26 Dec 2024 14:12:47 +0900 -Subject: tracing: Add ftrace_partial_regs() for converting ftrace_regs to - pt_regs - -From: Masami Hiramatsu (Google) - -[ Upstream commit b9b55c8912ce1e5555715d126486bdd63ddfeaec ] - -Add ftrace_partial_regs() which converts the ftrace_regs to pt_regs. -This is for the eBPF which needs this to keep the same pt_regs interface -to access registers. -Thus when replacing the pt_regs with ftrace_regs in fprobes (which is -used by kprobe_multi eBPF event), this will be used. - -If the architecture defines its own ftrace_regs, this copies partial -registers to pt_regs and returns it. If not, ftrace_regs is the same as -pt_regs and ftrace_partial_regs() will return ftrace_regs::regs. - -Signed-off-by: Masami Hiramatsu (Google) -Acked-by: Florent Revest -Cc: Alexei Starovoitov -Cc: Martin KaFai Lau -Cc: bpf -Cc: Alexei Starovoitov -Cc: Jiri Olsa -Cc: Alan Maguire -Cc: Mark Rutland -Cc: Catalin Marinas -Cc: Will Deacon -Cc: Paul Walmsley -Cc: Palmer Dabbelt -Cc: Albert Ou -Link: https://lore.kernel.org/173518996761.391279.4987911298206448122.stgit@devnote2 -Signed-off-by: Steven Rostedt (Google) -Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args") -Signed-off-by: Sasha Levin ---- - arch/arm64/include/asm/ftrace.h | 13 +++++++++++++ - arch/riscv/include/asm/ftrace.h | 14 ++++++++++++++ - include/linux/ftrace.h | 17 +++++++++++++++++ - 3 files changed, 44 insertions(+) - -diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h -index b5fa57b61378e..09210f853f12d 100644 ---- a/arch/arm64/include/asm/ftrace.h -+++ b/arch/arm64/include/asm/ftrace.h -@@ -135,6 +135,19 @@ ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs) - return arch_ftrace_regs(fregs)->fp; - } - -+static __always_inline struct pt_regs * -+ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) -+{ -+ struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs); -+ -+ memcpy(regs->regs, afregs->regs, sizeof(afregs->regs)); -+ regs->sp = afregs->sp; -+ regs->pc = afregs->pc; -+ regs->regs[29] = afregs->fp; -+ regs->regs[30] = afregs->lr; -+ return regs; -+} -+ - int ftrace_regs_query_register_offset(const char *name); - - int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); -diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h -index 9372f8d7036f8..7064a530794b6 100644 ---- a/arch/riscv/include/asm/ftrace.h -+++ b/arch/riscv/include/asm/ftrace.h -@@ -197,6 +197,20 @@ static __always_inline void ftrace_override_function_with_return(struct ftrace_r - arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra; - } - -+static __always_inline struct pt_regs * -+ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) -+{ -+ struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs); -+ -+ memcpy(®s->a0, afregs->args, sizeof(afregs->args)); -+ regs->epc = afregs->epc; -+ regs->ra = afregs->ra; -+ regs->sp = afregs->sp; -+ regs->s0 = afregs->s0; -+ regs->t1 = afregs->t1; -+ return regs; -+} -+ - int ftrace_regs_query_register_offset(const char *name); - - void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, -diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h -index 46ac44366c90a..863c014dff683 100644 ---- a/include/linux/ftrace.h -+++ b/include/linux/ftrace.h -@@ -190,6 +190,23 @@ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs - return arch_ftrace_get_regs(fregs); - } - -+#if !defined(CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS) || \ -+ defined(CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS) -+ -+static __always_inline struct pt_regs * -+ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs) -+{ -+ /* -+ * If CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS=y, ftrace_regs memory -+ * layout is including pt_regs. So always returns that address. -+ * Since arch_ftrace_get_regs() will check some members and may return -+ * NULL, we can not use it. -+ */ -+ return &arch_ftrace_regs(fregs)->regs; -+} -+ -+#endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */ -+ - /* - * When true, the ftrace_regs_{get,set}_*() functions may be used on fregs. - * Note: this can be true even when ftrace_get_regs() cannot provide a pt_regs. --- -2.39.5 - diff --git a/queue-6.13/tracing-fprobe-events-log-error-for-exceeding-the-nu.patch b/queue-6.13/tracing-fprobe-events-log-error-for-exceeding-the-nu.patch deleted file mode 100644 index 5886cd0f44..0000000000 --- a/queue-6.13/tracing-fprobe-events-log-error-for-exceeding-the-nu.patch +++ /dev/null @@ -1,59 +0,0 @@ -From b9d5ba4f995b836db2e9dfec82979f43671868b0 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Wed, 26 Feb 2025 15:19:02 +0900 -Subject: tracing: fprobe-events: Log error for exceeding the number of entry - args - -From: Masami Hiramatsu (Google) - -[ Upstream commit db5e228611b118cf7b1f8084063feda5c037f4a7 ] - -Add error message when the number of entry argument exceeds the -maximum size of entry data. -This is currently checked when registering fprobe, but in this case -no error message is shown in the error_log file. - -Link: https://lore.kernel.org/all/174055074269.4079315.17809232650360988538.stgit@mhiramat.tok.corp.google.com/ - -Fixes: 25f00e40ce79 ("tracing/probes: Support $argN in return probe (kprobe and fprobe)") -Signed-off-by: Masami Hiramatsu (Google) -Reviewed-by: Steven Rostedt (Google) -Signed-off-by: Sasha Levin ---- - kernel/trace/trace_fprobe.c | 5 +++++ - kernel/trace/trace_probe.h | 3 ++- - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c -index d906baba2d40c..94fe261218771 100644 ---- a/kernel/trace/trace_fprobe.c -+++ b/kernel/trace/trace_fprobe.c -@@ -1242,6 +1242,11 @@ static int __trace_fprobe_create(int argc, const char *argv[]) - if (is_return && tf->tp.entry_arg) { - tf->fp.entry_handler = trace_fprobe_entry_handler; - tf->fp.entry_data_size = traceprobe_get_entry_data_size(&tf->tp); -+ if (ALIGN(tf->fp.entry_data_size, sizeof(long)) > MAX_FPROBE_DATA_SIZE) { -+ trace_probe_log_set_index(2); -+ trace_probe_log_err(0, TOO_MANY_EARGS); -+ return -E2BIG; -+ } - } - - ret = traceprobe_set_print_fmt(&tf->tp, -diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h -index fba3ede870541..c47ca002347a7 100644 ---- a/kernel/trace/trace_probe.h -+++ b/kernel/trace/trace_probe.h -@@ -545,7 +545,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, - C(NO_BTF_FIELD, "This field is not found."), \ - C(BAD_BTF_TID, "Failed to get BTF type info."),\ - C(BAD_TYPE4STR, "This type does not fit for string."),\ -- C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"), -+ C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\ -+ C(TOO_MANY_EARGS, "Too many entry arguments specified"), - - #undef C - #define C(a, b) TP_ERR_##a --- -2.39.5 -