[PATCH] ARM: Add HAVE_FUNCTION_ARG_ACCESS_API support

From: Jinjie Ruan
Date: Mon Jun 03 2024 - 03:36:42 EST


Currently, kprobe on ARM32 can not use the '$argx' syntax available on
other architecture. So implement regs_get_kernel_argument() and add
HAVE_FUNCTION_ARG_ACCESS_API support.

Before there is a following error:
echo 'p:kprobe_submit_bio submit_bio bio=$arg1' > kprobe_events
sh: write error: Invalid argument

After:
# echo 'p:kprobe_submit_bio submit_bio bio=$arg1' > kprobe_events
# echo 1 > events/kprobes/enable
# echo 1 > events/kprobes/kprobe_submit_bio/enable
# echo 0 > tracing_on
# echo > trace
# echo 1 > tracing_on
# cat trace
kworker/u19:0-36 [002] d.... 54.175322: kprobe_submit_bio: (submit_bio+0x0/0xf8) bio=0xc24e6000

Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/ptrace.h | 22 ++++++++++++++++++++++
2 files changed, 23 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ee5115252aac..4ed504139763 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -102,6 +102,7 @@ config ARM
select HAVE_EXIT_THREAD
select HAVE_GUP_FAST if ARM_LPAE
select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
+ select HAVE_FUNCTION_ARG_ACCESS_API
select HAVE_FUNCTION_ERROR_INJECTION
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER if !XIP_KERNEL
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 6eb311fb2da0..da5dd4cd0324 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -52,6 +52,28 @@ struct svc_pt_regs {
#define fast_interrupts_enabled(regs) \
(!((regs)->ARM_cpsr & PSR_F_BIT))

+/**
+ * regs_get_kernel_argument() - get Nth function argument in kernel
+ * @regs: pt_regs of that context
+ * @n: function argument number (start from 0)
+ *
+ * regs_get_argument() returns @n th argument of the function call.
+ *
+ * Note that this chooses the most likely register mapping. In very rare
+ * cases this may not return correct data, for example, if one of the
+ * function parameters is 16 bytes or bigger. In such cases, we cannot
+ * get access the parameter correctly and the register assignment of
+ * subsequent parameters will be shifted.
+ */
+static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
+ unsigned int n)
+{
+#define NR_REG_ARGUMENTS 4
+ if (n < NR_REG_ARGUMENTS)
+ return regs->uregs[n];
+ return 0;
+}
+
/* Are the current registers suitable for user mode?
* (used to maintain security in signal handlers)
*/
--
2.34.1