From: Masami Hiramatsu (Google) <mhira...@kernel.org>

Add get_entry_ip() implementation for arm64. This is based on the
information in ftrace_call_adjust() on arm64. Basically function entry
address = ftrace call entry_ip - 4, but when there is a BTI at the first
instruction, we need one more instruction back (entry_ip - 8.)

Signed-off-by: Masami Hiramatsu (Google) <mhira...@kernel.org>
---
 kernel/trace/bpf_trace.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index deb629f4a510..60e7ff16f56f 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1066,6 +1066,70 @@ static unsigned long get_entry_ip(unsigned long 
fentry_ip)
                fentry_ip -= ENDBR_INSN_SIZE;
        return fentry_ip;
 }
+#elif defined(CONFIG_ARM64)
+#include <asm/insn.h>
+
+static unsigned long get_entry_ip(unsigned long fentry_ip)
+{
+       u32 insn;
+
+       /*
+        * When using patchable-function-entry without pre-function NOPS, ftrace
+        * entry is the address of the first NOP after the function entry point.
+        *
+        * The compiler has either generated:
+        *
+        * func+00:     func:   NOP             // To be patched to MOV X9, LR
+        * func+04:             NOP             // To be patched to BL <caller>
+        *
+        * Or:
+        *
+        * func-04:             BTI     C
+        * func+00:     func:   NOP             // To be patched to MOV X9, LR
+        * func+04:             NOP             // To be patched to BL <caller>
+        *
+        * The fentry_ip is the address of `BL <caller>` which is at `func + 4`
+        * bytes in either case.
+        */
+       if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
+               return fentry_ip - AARCH64_INSN_SIZE;
+
+       /*
+        * When using patchable-function-entry with pre-function NOPs, BTI is
+        * a bit different.
+        *
+        * func+00:     func:   NOP             // To be patched to MOV X9, LR
+        * func+04:             NOP             // To be patched to BL <caller>
+        *
+        * Or:
+        *
+        * func+00:     func:   BTI     C
+        * func+04:             NOP             // To be patched to MOV X9, LR
+        * func+08:             NOP             // To be patched to BL <caller>
+        *
+        * The fentry_ip is the address of `BL <caller>` which is at either
+        * `func + 4` or `func + 8` depends on whether there is a BTI.
+        */
+
+       /* If there is no BTI, the func address should be one instruction 
before. */
+       if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
+               return fentry_ip - AARCH64_INSN_SIZE;
+
+       /* We want to be extra safe in case entry ip is on the page edge,
+        * but otherwise we need to avoid get_kernel_nofault()'s overhead.
+        */
+       if ((fentry_ip & ~PAGE_MASK) < AARCH64_INSN_SIZE * 2) {
+               if (get_kernel_nofault(insn, (u32 *)(fentry_ip - 
AARCH64_INSN_SIZE * 2)))
+                       return fentry_ip - AARCH64_INSN_SIZE;
+       } else {
+               insn = *(u32 *)(fentry_ip - AARCH64_INSN_SIZE * 2);
+       }
+
+       if (aarch64_insn_is_bti(le32_to_cpu((__le32)insn)))
+               return fentry_ip - AARCH64_INSN_SIZE * 2;
+
+       return fentry_ip - AARCH64_INSN_SIZE;
+}
 #else
 #define get_entry_ip(fentry_ip) fentry_ip
 #endif


Reply via email to