This patch depends on the compiler's mfentry feature for arm64 that
proposed by this patchset. If the kernel is compiled with this feature,
the entry of each function like:
   foo:
       mov x9, x30
       bl __fentry__
       mov x30, x9
When -mfentry is used, the call is to '__fentry__' and not '_mcount'
and is done before the function's stack frame is set up. So __fentry__
is responsibel to protect parameter registers and corruptible registers.

Signed-off-by: Li Bin <huawei.li...@huawei.com>
---
 arch/arm64/Kconfig               |    1 +
 arch/arm64/include/asm/ftrace.h  |    5 +++
 arch/arm64/kernel/arm64ksyms.c   |    4 ++
 arch/arm64/kernel/entry-ftrace.S |   59 +++++++++++++++++++++++++++++++++++--
 scripts/recordmcount.pl          |    2 +-
 5 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index ea435c9..7bb2468 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -60,6 +60,7 @@ config ARM64
        select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
        select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_FENTRY
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_GENERIC_DMA_COHERENT
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index a7722b9..08eab52 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -13,7 +13,11 @@
 
 #include <asm/insn.h>
 
+#ifdef CC_USING_FENTRY
+#define MCOUNT_ADDR            ((unsigned long)__fentry__)
+#else
 #define MCOUNT_ADDR            ((unsigned long)_mcount)
+#endif
 #define MCOUNT_INSN_SIZE       AARCH64_INSN_SIZE
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -24,6 +28,7 @@
 #include <linux/compat.h>
 
 extern void _mcount(unsigned long);
+extern void __fentry__(unsigned long);
 extern void *return_address(unsigned int);
 
 struct dyn_arch_ftrace {
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index a85843d..f0455d3 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -63,5 +63,9 @@ EXPORT_SYMBOL(change_bit);
 EXPORT_SYMBOL(test_and_change_bit);
 
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_FENTRY
+EXPORT_SYMBOL(__fentry__);
+#else
 EXPORT_SYMBOL(_mcount);
 #endif
+#endif
diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
index fde793b..18cfe5b 100644
--- a/arch/arm64/kernel/entry-ftrace.S
+++ b/arch/arm64/kernel/entry-ftrace.S
@@ -93,27 +93,57 @@
        ldr     \reg, [\reg]
        .endm
 
+       /* for instrumented function's parent */
+       .macro fentry_get_parent_fp reg
+       ldr     \reg, [x29]
+       .endm
+
        /* for instrumented function */
        .macro mcount_get_pc0 reg
        mcount_adjust_addr      \reg, x30
        .endm
 
+       /* for instrumented function */
+       .macro fentry_get_pc0 reg
+       mcount_adjust_addr      \reg, x30
+       .endm
+
        .macro mcount_get_pc reg
        ldr     \reg, [x29, #8]
        mcount_adjust_addr      \reg, \reg
        .endm
 
+       .macro fentry_get_pc reg
+       ldr     \reg, [x29, #8]
+       mcount_adjust_addr      \reg, \reg
+       .endm
+
        .macro mcount_get_lr reg
        ldr     \reg, [x29]
        ldr     \reg, [\reg, #8]
        mcount_adjust_addr      \reg, \reg
        .endm
 
+       .macro fentry_get_lr reg, base
+       ldr     \reg, [\base, #72]      //S_X9
+       mcount_adjust_addr      \reg, \reg
+       .endm
+
        .macro mcount_get_lr_addr reg
        ldr     \reg, [x29]
        add     \reg, \reg, #8
        .endm
 
+       .macro fentry_get_lr_addr reg, base
+       add     \reg, \base, #72        //S_X9
+       .endm
+
+#ifdef CC_USING_FENTRY
+#define        function_hook   __fentry__
+#else
+#define        function_hook   _mcount
+#endif
+
 #ifndef CONFIG_DYNAMIC_FTRACE
 /*
  * void _mcount(unsigned long return_address)
@@ -123,7 +153,7 @@
  *     - tracer function to probe instrumented function's entry,
  *     - ftrace_graph_caller to set up an exit hook
  */
-ENTRY(_mcount)
+ENTRY(function_hook)
        mcount_enter
        save_mcount_regs
 
@@ -133,8 +163,13 @@ ENTRY(_mcount)
        cmp     x0, x2                  // if (ftrace_trace_function
        b.eq    skip_ftrace_call        //     != ftrace_stub) {
 
+#ifdef CC_USING_FENTRY
+       fentry_get_pc   x0              //       function's pc
+       fentry_get_lr   x1, sp          //       function's lr (= parent's pc)
+#else
        mcount_get_pc   x0              //       function's pc
        mcount_get_lr   x1              //       function's lr (= parent's pc)
+#endif
        blr     x2                      //   (*ftrace_trace_function)(pc, lr);
 
 #ifndef CONFIG_FUNCTION_GRAPH_TRACER
@@ -161,7 +196,7 @@ skip_ftrace_call:
        restore_mcount_regs
        mcount_exit
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-ENDPROC(_mcount)
+ENDPROC(function_hook)
 
 #else /* CONFIG_DYNAMIC_FTRACE */
 /*
@@ -170,9 +205,9 @@ ENDPROC(_mcount)
  * and later on, NOP to branch to ftrace_caller() when enabled or branch to
  * NOP when disabled per-function base.
  */
-ENTRY(_mcount)
+ENTRY(function_hook)
        ret
-ENDPROC(_mcount)
+ENDPROC(function_hook)
 
 /*
  * void ftrace_caller(unsigned long return_address)
@@ -189,8 +224,13 @@ ENTRY(ftrace_caller)
 
        adrp    x0, function_trace_op
        ldr     x2, [x0, #:lo12:function_trace_op]
+#ifdef CC_USING_FENTRY
+       fentry_get_pc0  x0              //     function's pc
+       fentry_get_lr   x1, sp          //     function's lr
+#else
        mcount_get_pc0  x0              //     function's pc
        mcount_get_lr   x1              //     function's lr
+#endif
        mov     x3, #0
 
        .global ftrace_call
@@ -237,8 +277,13 @@ ENTRY(ftrace_regs_caller)
 
        adrp    x0, function_trace_op
        ldr     x2, [x0, #:lo12:function_trace_op]
+#ifdef CC_USING_FENTRY
+       fentry_get_pc0  x0              //     function's pc
+       fentry_get_lr   x1, sp          //     function's lr
+#else
        mcount_get_pc0  x0              //     function's pc
        mcount_get_lr   x1              //     function's lr
+#endif
        mov     x3, sp
 
        .global ftrace_regs_call
@@ -282,9 +327,15 @@ ENDPROC(ftrace_stub)
  * and run return_to_handler() later on its exit.
  */
 ENTRY(ftrace_graph_caller)
+#ifdef CC_USING_FENTRY
+       fentry_get_lr_addr      x0, sp  //     pointer to function's saved lr
+       fentry_get_pc           x1      //     function's pc
+       fentry_get_parent_fp    x2      //     parent's fp
+#else
        mcount_get_lr_addr        x0    //     pointer to function's saved lr
        mcount_get_pc             x1    //     function's pc
        mcount_get_parent_fp      x2    //     parent's fp
+#endif
        bl      prepare_ftrace_return   // prepare_ftrace_return(&lr, pc, fp)
 
        restore_mcount_regs
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 826470d..5020d96 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -279,7 +279,7 @@ if ($arch eq "x86_64") {
 } elsif ($arch eq "arm64") {
     $alignment = 3;
     $section_type = '%progbits';
-    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+_mcount\$";
+    $mcount_regex = 
"^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+(_mcount|__fentry__)\$";
     $type = ".quad";
 } elsif ($arch eq "ia64") {
     $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to