summaryrefslogtreecommitdiff
path: root/arch/blackfin/kernel/ftrace-entry.S
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-06-10 04:45:29 -0400
committerMike Frysinger <vapier@gentoo.org>2009-06-13 07:20:16 -0400
commit1ee76d7e169ff2b0ff1df4b40b9d5276eec9ffb4 (patch)
tree384f296a2e24ee0156a81d9b62cdf6bc48d10650 /arch/blackfin/kernel/ftrace-entry.S
parent1c873be744410e26fb91ee9228c90adff6eabe15 (diff)
Blackfin: initial support for ftrace grapher
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/kernel/ftrace-entry.S')
-rw-r--r--arch/blackfin/kernel/ftrace-entry.S68
1 files changed, 68 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S
index ce71487b515f..6980b7a0615d 100644
--- a/arch/blackfin/kernel/ftrace-entry.S
+++ b/arch/blackfin/kernel/ftrace-entry.S
@@ -35,6 +35,28 @@ ENTRY(__mcount)
cc = r2 == r3;
if ! cc jump .Ldo_trace;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ /* if the ftrace_graph_return function pointer is not set to
+ * the ftrace_stub entry, call prepare_ftrace_return().
+ */
+ p0.l = _ftrace_graph_return;
+ p0.h = _ftrace_graph_return;
+ r3 = [p0];
+ cc = r2 == r3;
+ if ! cc jump _ftrace_graph_caller;
+
+ /* similarly, if the ftrace_graph_entry function pointer is not
+ * set to the ftrace_graph_entry_stub entry, ...
+ */
+ p0.l = _ftrace_graph_entry;
+ p0.h = _ftrace_graph_entry;
+ r2.l = _ftrace_graph_entry_stub;
+ r2.h = _ftrace_graph_entry_stub;
+ r3 = [p0];
+ cc = r2 == r3;
+ if ! cc jump _ftrace_graph_caller;
+#endif
+
r2 = [sp++];
rts;
@@ -61,6 +83,7 @@ ENTRY(__mcount)
call (p0);
/* restore state and get out of dodge */
+.Lfinish_trace:
rets = [sp++];
r1 = [sp++];
r0 = [sp++];
@@ -70,3 +93,48 @@ ENTRY(__mcount)
_ftrace_stub:
rts;
ENDPROC(__mcount)
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/* The prepare_ftrace_return() function is similar to the trace function
+ * except it takes a pointer to the location of the frompc. This is so
+ * the prepare_ftrace_return() can hijack it temporarily for probing
+ * purposes.
+ */
+ENTRY(_ftrace_graph_caller)
+ /* save first/second function arg and the return register */
+ [--sp] = r0;
+ [--sp] = r1;
+ [--sp] = rets;
+
+ r0 = fp;
+ r1 = rets;
+ r0 += 4;
+ r1 += -MCOUNT_INSN_SIZE;
+ call _prepare_ftrace_return;
+
+ jump .Lfinish_trace;
+ENDPROC(_ftrace_graph_caller)
+
+/* Undo the rewrite caused by ftrace_graph_caller(). The common function
+ * ftrace_return_to_handler() will return the original rets so we can
+ * restore it and be on our way.
+ */
+ENTRY(_return_to_handler)
+ /* make sure original return values are saved */
+ [--sp] = p0;
+ [--sp] = r0;
+ [--sp] = r1;
+
+ /* get original return address */
+ call _ftrace_return_to_handler;
+ rets = r0;
+
+ /* anomaly 05000371 - make sure we have at least three instructions
+ * between rets setting and the return
+ */
+ r1 = [sp++];
+ r0 = [sp++];
+ p0 = [sp++];
+ rts;
+ENDPROC(_return_to_handler)
+#endif