summary refs log tree commit diff
path: root/arch/csky/kernel
diff options
context:
space:
mode:
authorGuo Ren <ren_guo@c-sky.com>2018-12-15 21:04:27 +0800
committerGuo Ren <ren_guo@c-sky.com>2018-12-31 23:17:23 +0800
commitd7950be145c84ca5094c52bc1ad1e7f1893d0f19 (patch)
treec69b59c597f07f36159112ad3afc251feb32455e /arch/csky/kernel
parent230c77a5e92a29bf21e98ee35e22b0537f61c55b (diff)
downloadlinux-d7950be145c84ca5094c52bc1ad1e7f1893d0f19.tar.gz
csky: ftrace call graph supported.
With csky-gcc -pg -mbacktrace, ftrace call graph supported.

Signed-off-by: Guo Ren <ren_guo@c-sky.com>
Diffstat (limited to 'arch/csky/kernel')
-rw-r--r--arch/csky/kernel/ftrace.c48
1 files changed, 37 insertions, 11 deletions
diff --git a/arch/csky/kernel/ftrace.c b/arch/csky/kernel/ftrace.c
index ad054f7190f9..274c431f1810 100644
--- a/arch/csky/kernel/ftrace.c
+++ b/arch/csky/kernel/ftrace.c
@@ -4,21 +4,47 @@
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
-extern void (*ftrace_trace_function)(unsigned long, unsigned long,
-				     struct ftrace_ops*, struct pt_regs*);
+#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;
+	unsigned long old;
 
+	if (unlikely(atomic_read(&current->tracing_graph_pause)))
+		return;
 
-noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
-				  struct ftrace_ops *op, struct pt_regs *regs)
-{
-	asm volatile ("\n");
-}
+	old = *parent;
 
-noinline void csky_mcount(unsigned long from_pc, unsigned long self_pc)
-{
-	if (ftrace_trace_function != ftrace_stub)
-		ftrace_trace_function(self_pc, from_pc, NULL, NULL);
+	if (!function_graph_enter(old, self_addr,
+			*(unsigned long *)frame_pointer, parent)) {
+		/*
+		 * For csky-gcc function has sub-call:
+		 * subi	sp,	sp, 8
+		 * stw	r8,	(sp, 0)
+		 * mov	r8,	sp
+		 * st.w r15,	(sp, 0x4)
+		 * push	r15
+		 * jl	_mcount
+		 * We only need set *parent for resume
+		 *
+		 * For csky-gcc function has no sub-call:
+		 * subi	sp,	sp, 4
+		 * stw	r8,	(sp, 0)
+		 * mov	r8,	sp
+		 * push	r15
+		 * jl	_mcount
+		 * We need set *parent and *(frame_pointer + 4) for resume,
+		 * because lr is resumed twice.
+		 */
+		*parent = return_hooker;
+		frame_pointer += 4;
+		if (*(unsigned long *)frame_pointer == old)
+			*(unsigned long *)frame_pointer = return_hooker;
+	}
 }
+#endif
 
 /* _mcount is defined in abi's mcount.S */
+extern void _mcount(void);
 EXPORT_SYMBOL(_mcount);