Ftrace operations require that DYNAMIC_FTRACE_WITH_REGS is enabled.
This patch introduces a new ftrace handler that store the registers on the
stack before calling the next stage. The registers are also restored from the
stack before going back to the instrumented function.

Signed-off-by: Jean-Jacques Hiblot <[email protected]>
---
 arch/arm/Kconfig               |  2 ++
 arch/arm/include/asm/ftrace.h  |  3 ++
 arch/arm/kernel/entry-common.S | 68 +++++++++++++++++++++++++++++++++++++++++-
 arch/arm/kernel/ftrace.c       | 34 +++++++++++++++++++++
 4 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 32cbbd5..6f928ee 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -39,6 +39,7 @@ config ARM
        select HAVE_DMA_ATTRS
        select HAVE_DMA_CONTIGUOUS if MMU
        select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
        select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) 
&& MMU
        select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
        select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
@@ -72,6 +73,7 @@ config ARM
        select PERF_USE_VMALLOC
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
+       select FRAME_POINTER if DYNAMIC_FTRACE_WITH_REGS && 
FUNCTION_GRAPH_TRACER
        # Above selects are sorted alphabetically; please add new ones
        # according to that.  Thanks.
        help
diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h
index 39eb16b..d8e9bea 100644
--- a/arch/arm/include/asm/ftrace.h
+++ b/arch/arm/include/asm/ftrace.h
@@ -10,6 +10,9 @@ extern void mcount(void);
 extern void __gnu_mcount_nc(void);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
+
+#define ARCH_SUPPORTS_FTRACE_OPS 1
+
 struct dyn_arch_ftrace {
 #ifdef CONFIG_OLD_MCOUNT
        bool    old_mcount;
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e52fe5a..9594fe2 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -197,7 +197,10 @@ ENDPROC(ret_from_fork)
 
        mcount_get_lr   r1                      @ lr of instrumented func
        mcount_adjust_addr      r0, lr          @ instrumented function
-
+       ldr r2, =function_trace_op
+       ldr r2, [r2]                            @ pointer to the current
+                                               @ function tracing op
+       mov r3, #0                              @ regs is NULL
        .globl ftrace_call\suffix
 ftrace_call\suffix:
        bl      ftrace_stub
@@ -211,6 +214,38 @@ ftrace_graph_call\suffix:
        mcount_exit
 .endm
 
+.macro __ftrace_regs_caller
+
+       add     ip, sp, #4      @ move in IP the value of SP as it was
+                               @ before the push {lr} of the mcount mechanism
+       stmdb   sp!, {ip,lr,pc}
+       stmdb   sp!, {r0-r11,lr}
+       @ stack content  at this point:
+       @ 0  4         44    48   52       56   60   64
+       @ RO | R1 | ... | R11 | LR | SP + 4 | LR | PC | previous LR |
+
+       mov r3, sp                              @ struct pt_regs*
+       ldr r2, =function_trace_op
+       ldr r2, [r2]                            @ pointer to the current
+                                               @ function tracing op
+       ldr     r1, [sp, #64]                   @ lr of instrumented func
+       mcount_adjust_addr      r0, lr          @ instrumented function
+
+       .globl ftrace_regs_call
+ftrace_regs_call:
+       bl      ftrace_stub
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       .globl ftrace_graph_regs_call
+ftrace_graph_regs_call:
+       mov     r0, r0
+#endif
+       ldr     lr, [sp, #64]           @ get the previous LR value from stack
+       ldmia   sp, {r0-r11, ip, sp}    @ pop the saved registers INCLUDING
+                                       @ the stack pointer
+       ret     ip
+.endm
+
 .macro __ftrace_graph_caller
        sub     r0, fp, #4              @ &lr of instrumented routine (&parent)
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -226,6 +261,24 @@ ftrace_graph_call\suffix:
        mcount_exit
 .endm
 
+
+.macro __ftrace_graph_regs_caller
+
+       sub     r0, fp, #4              @ &lr of instrumented routine (&parent)
+
+       @ called from __ftrace_regs_caller
+       ldr     r1, [sp, #56]           @ instrumented routine (func)
+       mcount_adjust_addr      r1, r1
+
+       mov     r2, fp                  @ frame pointer
+       bl      prepare_ftrace_return
+
+       ldr     lr, [fp, #-4]           @ restore LR from the stack
+       ldmia   sp, {r0-r11, ip, sp}    @ pop the saved registers INCLUDING
+                                       @ the stack pointer
+       ret     ip
+.endm
+
 #ifdef CONFIG_OLD_MCOUNT
 /*
  * mcount
@@ -312,14 +365,27 @@ UNWIND(.fnstart)
        __ftrace_caller
 UNWIND(.fnend)
 ENDPROC(ftrace_caller)
+
+ENTRY(ftrace_regs_caller)
+UNWIND(.fnstart)
+       __ftrace_regs_caller
+UNWIND(.fnend)
+ENDPROC(ftrace_regs_caller)
 #endif
 
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 ENTRY(ftrace_graph_caller)
 UNWIND(.fnstart)
        __ftrace_graph_caller
 UNWIND(.fnend)
 ENDPROC(ftrace_graph_caller)
+
+ENTRY(ftrace_graph_regs_caller)
+UNWIND(.fnstart)
+       __ftrace_graph_regs_caller
+UNWIND(.fnend)
+ENDPROC(ftrace_graph_regs_caller)
 #endif
 
 .purgem mcount_enter
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index af9a8a9..35c5743 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -130,6 +130,16 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        }
 #endif
 
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+       if (!ret) {
+               pc = (unsigned long)&ftrace_regs_call;
+               new = ftrace_call_replace(pc, (unsigned long)func);
+
+               ret = ftrace_modify_code(pc, 0, new, false);
+       }
+#endif
+
        return ret;
 }
 
@@ -139,6 +149,20 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long 
addr)
        unsigned long ip = rec->ip;
 
        old = ftrace_nop_replace(rec);
+
+       new = ftrace_call_replace(ip, adjust_address(rec, addr));
+
+       return ftrace_modify_code(rec->ip, old, new, true);
+}
+
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+                               unsigned long addr)
+{
+       unsigned long new, old;
+       unsigned long ip = rec->ip;
+
+       old = ftrace_call_replace(ip, adjust_address(rec, old_addr));
+
        new = ftrace_call_replace(ip, adjust_address(rec, addr));
 
        return ftrace_modify_code(rec->ip, old, new, true);
@@ -211,6 +235,9 @@ void prepare_ftrace_return(unsigned long *parent, unsigned 
long self_addr,
 extern unsigned long ftrace_graph_call;
 extern unsigned long ftrace_graph_call_old;
 extern void ftrace_graph_caller_old(void);
+extern unsigned long ftrace_graph_regs_call;
+extern void ftrace_graph_regs_caller(void);
+
 
 static int __ftrace_modify_caller(unsigned long *callsite,
                                  void (*func) (void), bool enable)
@@ -240,6 +267,13 @@ static int ftrace_modify_graph_caller(bool enable)
                                             enable);
 #endif
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+       if (!ret)
+               ret = __ftrace_modify_caller(&ftrace_graph_regs_call,
+                                    ftrace_graph_regs_caller,
+                                    enable);
+#endif
+
        return ret;
 }
 
-- 
2.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
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