|
@@ -0,0 +1,72 @@
|
|
|
|
+/*
|
|
|
|
+ * mcount and friends -- ftrace stuff
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2009 Analog Devices Inc.
|
|
|
|
+ * Licensed under the GPL-2 or later.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#include <linux/linkage.h>
|
|
|
|
+#include <asm/ftrace.h>
|
|
|
|
+
|
|
|
|
+.text
|
|
|
|
+
|
|
|
|
+/* GCC will have called us before setting up the function prologue, so we
|
|
|
|
+ * can clobber the normal scratch registers, but we need to make sure to
|
|
|
|
+ * save/restore the registers used for argument passing (R0-R2) in case
|
|
|
|
+ * the profiled function is using them. With data registers, R3 is the
|
|
|
|
+ * only one we can blow away. With pointer registers, we have P0-P2.
|
|
|
|
+ *
|
|
|
|
+ * Upon entry, the RETS will point to the top of the current profiled
|
|
|
|
+ * function. And since GCC setup the frame for us, the previous function
|
|
|
|
+ * will be waiting there. mmmm pie.
|
|
|
|
+ */
|
|
|
|
+ENTRY(__mcount)
|
|
|
|
+ /* save third function arg early so we can do testing below */
|
|
|
|
+ [--sp] = r2;
|
|
|
|
+
|
|
|
|
+ /* load the function pointer to the tracer */
|
|
|
|
+ p0.l = _ftrace_trace_function;
|
|
|
|
+ p0.h = _ftrace_trace_function;
|
|
|
|
+ r3 = [p0];
|
|
|
|
+
|
|
|
|
+ /* optional micro optimization: don't call the stub tracer */
|
|
|
|
+ r2.l = _ftrace_stub;
|
|
|
|
+ r2.h = _ftrace_stub;
|
|
|
|
+ cc = r2 == r3;
|
|
|
|
+ if ! cc jump .Ldo_trace;
|
|
|
|
+
|
|
|
|
+ r2 = [sp++];
|
|
|
|
+ rts;
|
|
|
|
+
|
|
|
|
+.Ldo_trace:
|
|
|
|
+
|
|
|
|
+ /* save first/second function arg and the return register */
|
|
|
|
+ [--sp] = r0;
|
|
|
|
+ [--sp] = r1;
|
|
|
|
+ [--sp] = rets;
|
|
|
|
+
|
|
|
|
+ /* setup the tracer function */
|
|
|
|
+ p0 = r3;
|
|
|
|
+
|
|
|
|
+ /* tracer(ulong frompc, ulong selfpc):
|
|
|
|
+ * frompc: the pc that did the call to ...
|
|
|
|
+ * selfpc: ... this location
|
|
|
|
+ * the selfpc itself will need adjusting for the mcount call
|
|
|
|
+ */
|
|
|
|
+ r1 = rets;
|
|
|
|
+ r0 = [fp + 4];
|
|
|
|
+ r1 += -MCOUNT_INSN_SIZE;
|
|
|
|
+
|
|
|
|
+ /* call the tracer */
|
|
|
|
+ call (p0);
|
|
|
|
+
|
|
|
|
+ /* restore state and get out of dodge */
|
|
|
|
+ rets = [sp++];
|
|
|
|
+ r1 = [sp++];
|
|
|
|
+ r0 = [sp++];
|
|
|
|
+ r2 = [sp++];
|
|
|
|
+
|
|
|
|
+.globl _ftrace_stub
|
|
|
|
+_ftrace_stub:
|
|
|
|
+ rts;
|
|
|
|
+ENDPROC(__mcount)
|