+++ /dev/null
-From 8d08d4ef90d31596e14da03d051eaa3dc100344a Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 26 Dec 2024 14:11:55 +0900
-Subject: fgraph: Replace fgraph_ret_regs with ftrace_regs
-
-From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-
-[ 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) <mhiramat@kernel.org>
-Acked-by: Heiko Carstens <hca@linux.ibm.com>
-Acked-by: Will Deacon <will@kernel.org>
-Cc: Catalin Marinas <catalin.marinas@arm.com>
-Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
-Cc: Florent Revest <revest@chromium.org>
-Cc: Martin KaFai Lau <martin.lau@linux.dev>
-Cc: bpf <bpf@vger.kernel.org>
-Cc: Alexei Starovoitov <ast@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Alan Maguire <alan.maguire@oracle.com>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Huacai Chen <chenhuacai@kernel.org>
-Cc: WANG Xuerui <kernel@xen0n.name>
-Cc: Paul Walmsley <paul.walmsley@sifive.com>
-Cc: Palmer Dabbelt <palmer@dabbelt.com>
-Cc: Albert Ou <aou@eecs.berkeley.edu>
-Cc: Vasily Gorbik <gor@linux.ibm.com>
-Cc: Alexander Gordeev <agordeev@linux.ibm.com>
-Cc: Heiko Carstens <hca@linux.ibm.com>
-Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
-Cc: Sven Schnelle <svens@linux.ibm.com>
-Cc: Thomas Gleixner <tglx@linutronix.de>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: Borislav Petkov <bp@alien8.de>
-Cc: Dave Hansen <dave.hansen@linux.intel.com>
-Cc: x86@kernel.org
-Cc: "H. Peter Anvin" <hpa@zytor.com>
-Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
-Link: https://lore.kernel.org/173518991508.391279.16635322774382197642.stgit@devnote2
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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 <asm/asm-offsets.h>
- #include <asm/ftrace.h>
-
-+#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
-
+++ /dev/null
-From 98b2c6a182a85ab61910f92b12b78f066e34fd38 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 26 Dec 2024 14:13:59 +0900
-Subject: fprobe: Rewrite fprobe on function-graph tracer
-
-From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-
-[ 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) <mhiramat@kernel.org>
-Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
-Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
-Cc: Florent Revest <revest@chromium.org>
-Cc: Martin KaFai Lau <martin.lau@linux.dev>
-Cc: bpf <bpf@vger.kernel.org>
-Cc: Alexei Starovoitov <ast@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Alan Maguire <alan.maguire@oracle.com>
-Cc: Heiko Carstens <hca@linux.ibm.com>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Catalin Marinas <catalin.marinas@arm.com>
-Cc: Will Deacon <will@kernel.org>
-Cc: Huacai Chen <chenhuacai@kernel.org>
-Cc: WANG Xuerui <kernel@xen0n.name>
-Cc: Michael Ellerman <mpe@ellerman.id.au>
-Cc: Nicholas Piggin <npiggin@gmail.com>
-Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
-Cc: Naveen N Rao <naveen@kernel.org>
-Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
-Cc: Paul Walmsley <paul.walmsley@sifive.com>
-Cc: Palmer Dabbelt <palmer@dabbelt.com>
-Cc: Albert Ou <aou@eecs.berkeley.edu>
-Cc: Vasily Gorbik <gor@linux.ibm.com>
-Cc: Alexander Gordeev <agordeev@linux.ibm.com>
-Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
-Cc: Sven Schnelle <svens@linux.ibm.com>
-Cc: Thomas Gleixner <tglx@linutronix.de>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: Borislav Petkov <bp@alien8.de>
-Cc: Dave Hansen <dave.hansen@linux.intel.com>
-Cc: x86@kernel.org
-Cc: "H. Peter Anvin" <hpa@zytor.com>
-Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
-Cc: Andrew Morton <akpm@linux-foundation.org>
-Link: https://lore.kernel.org/173519003970.391279.14406792285453830996.stgit@devnote2
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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 <linux/compiler.h>
- #include <linux/ftrace.h>
--#include <linux/rethook.h>
-+#include <linux/rcupdate.h>
-+#include <linux/refcount.h>
-+#include <linux/slab.h>
-
- 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 <linux/fprobe.h>
- #include <linux/kallsyms.h>
- #include <linux/kprobes.h>
--#include <linux/rethook.h>
-+#include <linux/list.h>
-+#include <linux/mutex.h>
- #include <linux/slab.h>
- #include <linux/sort.h>
-
- #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
-
+++ /dev/null
-From 96eedf4d4d07660c69478c2a7c41d8ceee750de6 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 26 Dec 2024 14:12:20 +0900
-Subject: fprobe: Use ftrace_regs in fprobe entry handler
-
-From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-
-[ 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 <alexei.starovoitov@gmail.com>
-Cc: Martin KaFai Lau <martin.lau@linux.dev>
-Cc: bpf <bpf@vger.kernel.org>
-Cc: Alexei Starovoitov <ast@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Alan Maguire <alan.maguire@oracle.com>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Link: https://lore.kernel.org/173518994037.391279.2786805566359674586.stgit@devnote2
-Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-Acked-by: Florent Revest <revest@chromium.org>
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 9ec816522c378200971176807181e023885863af Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 26 Dec 2024 14:12:31 +0900
-Subject: fprobe: Use ftrace_regs in fprobe exit handler
-
-From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-
-[ 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) <mhiramat@kernel.org>
-Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
-Cc: Huacai Chen <chenhuacai@kernel.org>
-Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
-Cc: Florent Revest <revest@chromium.org>
-Cc: bpf <bpf@vger.kernel.org>
-Cc: Alan Maguire <alan.maguire@oracle.com>
-Cc: Heiko Carstens <hca@linux.ibm.com>
-Cc: WANG Xuerui <kernel@xen0n.name>
-Cc: Vasily Gorbik <gor@linux.ibm.com>
-Cc: Alexander Gordeev <agordeev@linux.ibm.com>
-Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
-Cc: Sven Schnelle <svens@linux.ibm.com>
-Cc: Thomas Gleixner <tglx@linutronix.de>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: Borislav Petkov <bp@alien8.de>
-Cc: Dave Hansen <dave.hansen@linux.intel.com>
-Cc: x86@kernel.org
-Cc: "H. Peter Anvin" <hpa@zytor.com>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
-Cc: Song Liu <song@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: KP Singh <kpsingh@kernel.org>
-Cc: Matt Bobrowski <mattbobrowski@google.com>
-Cc: Alexei Starovoitov <ast@kernel.org>
-Cc: Daniel Borkmann <daniel@iogearbox.net>
-Cc: Andrii Nakryiko <andrii@kernel.org>
-Cc: Martin KaFai Lau <martin.lau@linux.dev>
-Cc: Eduard Zingerman <eddyz87@gmail.com>
-Cc: Yonghong Song <yonghong.song@linux.dev>
-Cc: John Fastabend <john.fastabend@gmail.com>
-Cc: Stanislav Fomichev <sdf@fomichev.me>
-Cc: Hao Luo <haoluo@google.com>
-Cc: Andrew Morton <akpm@linux-foundation.org>
-Link: https://lore.kernel.org/173518995092.391279.6765116450352977627.stgit@devnote2
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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
+++ /dev/null
-From 2dc177cc7af51eb92a7f8ee3b81edfcc1601d361 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 26 Dec 2024 14:12:59 +0900
-Subject: tracing: Add ftrace_fill_perf_regs() for perf event
-
-From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
-
-[ 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) <mhiramat@kernel.org>
-Acked-by: Will Deacon <will@kernel.org>
-Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
-Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
-Cc: Florent Revest <revest@chromium.org>
-Cc: Martin KaFai Lau <martin.lau@linux.dev>
-Cc: bpf <bpf@vger.kernel.org>
-Cc: Alexei Starovoitov <ast@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Alan Maguire <alan.maguire@oracle.com>
-Cc: Heiko Carstens <hca@linux.ibm.com>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Catalin Marinas <catalin.marinas@arm.com>
-Cc: Will Deacon <will@kernel.org>
-Cc: Michael Ellerman <mpe@ellerman.id.au>
-Cc: Nicholas Piggin <npiggin@gmail.com>
-Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
-Cc: Naveen N Rao <naveen@kernel.org>
-Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
-Cc: Vasily Gorbik <gor@linux.ibm.com>
-Cc: Alexander Gordeev <agordeev@linux.ibm.com>
-Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
-Cc: Sven Schnelle <svens@linux.ibm.com>
-Cc: Thomas Gleixner <tglx@linutronix.de>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: Borislav Petkov <bp@alien8.de>
-Cc: Dave Hansen <dave.hansen@linux.intel.com>
-Cc: x86@kernel.org
-Cc: "H. Peter Anvin" <hpa@zytor.com>
-Link: https://lore.kernel.org/173518997908.391279.15910334347345106424.stgit@devnote2
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From d610ad390f261355db36806d148174e492d32f0c Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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) <mhiramat@kernel.org>
-
-[ 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) <mhiramat@kernel.org>
-Acked-by: Florent Revest <revest@chromium.org>
-Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
-Cc: Martin KaFai Lau <martin.lau@linux.dev>
-Cc: bpf <bpf@vger.kernel.org>
-Cc: Alexei Starovoitov <ast@kernel.org>
-Cc: Jiri Olsa <jolsa@kernel.org>
-Cc: Alan Maguire <alan.maguire@oracle.com>
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Catalin Marinas <catalin.marinas@arm.com>
-Cc: Will Deacon <will@kernel.org>
-Cc: Paul Walmsley <paul.walmsley@sifive.com>
-Cc: Palmer Dabbelt <palmer@dabbelt.com>
-Cc: Albert Ou <aou@eecs.berkeley.edu>
-Link: https://lore.kernel.org/173518996761.391279.4987911298206448122.stgit@devnote2
-Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Stable-dep-of: db5e228611b1 ("tracing: fprobe-events: Log error for exceeding the number of entry args")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From b9d5ba4f995b836db2e9dfec82979f43671868b0 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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) <mhiramat@kernel.org>
-
-[ 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) <mhiramat@kernel.org>
-Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-