OSDN Git Service

nds32/ftrace: Support static function graph tracer
authorZong Li <zong@andestech.com>
Wed, 15 Aug 2018 02:53:04 +0000 (10:53 +0800)
committerGreentime Hu <greentime@andestech.com>
Tue, 4 Sep 2018 06:45:17 +0000 (14:45 +0800)
This patch contains implementation of static function graph tracer.

Signed-off-by: Zong Li <zong@andestech.com>
Acked-by: Greentime Hu <greentime@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
arch/nds32/Kconfig
arch/nds32/kernel/ftrace.c

index 853497f..ea171a0 100644 (file)
@@ -41,6 +41,7 @@ config NDS32
        select RTC_LIB
        select THREAD_INFO_IN_TASK
        select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_GRAPH_TRACER
        help
          Andes(nds32) Linux support.
 
index 563f64c..707fce7 100644 (file)
@@ -6,6 +6,8 @@
 
 extern void (*ftrace_trace_function)(unsigned long, unsigned long,
                                     struct ftrace_ops*, struct pt_regs*);
+extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
+extern void ftrace_graph_caller(void);
 
 noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
                                  struct ftrace_ops *op, struct pt_regs *regs)
@@ -23,6 +25,73 @@ noinline void _mcount(unsigned long parent_ip)
                ftrace_trace_function(ip - MCOUNT_INSN_SIZE, parent_ip,
                                      NULL, NULL);
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       if (ftrace_graph_return != (trace_func_graph_ret_t)ftrace_stub
+           || ftrace_graph_entry != ftrace_graph_entry_stub)
+               ftrace_graph_caller();
+#endif
+
        /* restore all state by the compiler epilogue */
 }
 EXPORT_SYMBOL(_mcount);
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+                          unsigned long frame_pointer)
+{
+       unsigned long return_hooker = (unsigned long)&return_to_handler;
+       struct ftrace_graph_ent trace;
+       unsigned long old;
+       int err;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+       old = *parent;
+
+       trace.func = self_addr;
+       trace.depth = current->curr_ret_stack + 1;
+
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace))
+               return;
+
+       err = ftrace_push_return_trace(old, self_addr, &trace.depth,
+                                      frame_pointer, NULL);
+
+       if (err == -EBUSY)
+               return;
+
+       *parent = return_hooker;
+}
+
+noinline void ftrace_graph_caller(void)
+{
+       unsigned long *parent_ip =
+               (unsigned long *)(__builtin_frame_address(2) - 4);
+
+       unsigned long selfpc =
+               (unsigned long)(__builtin_return_address(1) - MCOUNT_INSN_SIZE);
+
+       unsigned long frame_pointer =
+               (unsigned long)__builtin_frame_address(3);
+
+       prepare_ftrace_return(parent_ip, selfpc, frame_pointer);
+}
+
+extern unsigned long ftrace_return_to_handler(unsigned long frame_pointer);
+void __naked return_to_handler(void)
+{
+       __asm__ __volatile__ (
+               /* save state needed by the ABI     */
+               "smw.adm $r0,[$sp],$r1,#0x0  \n\t"
+
+               /* get original return address      */
+               "move $r0, $fp               \n\t"
+               "bal ftrace_return_to_handler\n\t"
+               "move $lp, $r0               \n\t"
+
+               /* restore state nedded by the ABI  */
+               "lmw.bim $r0,[$sp],$r1,#0x0  \n\t");
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */