[PATCH v3] mips function graph tracer support

From: Wu Zhangjin
Date: Sun Jun 14 2009 - 11:53:36 EST


From: Wu Zhangjin <wuzj@xxxxxxxxxx>

this works something like -finstrument-functions does, instead of using

void __cyg_profile_func_enter (void *this_fn,
void *call_site);
void __cyg_profile_func_exit (void *this_fn,
void *call_site);

-pg use _mcount, so some tricks are adoptive by the author of orignal function
graph tracer:

the _mcount function will call prepare_function_return to save the
parent_ip, ip and calltime in a tracing array, if success, the
address of a hooker function &return_to_handler will be substitued
to the parent_ip, so, after return from _mcount it will call the
&return_to_handler, not back to the parent_ip, but calling
ftrace_return_to_handler to remember the rettime, and return the
parent_ip to let &return_to_handler go back to the real parent.

Reviewed-by: Steven Rostedt <rostedt@xxxxxxxxxxx>
Signed-off-by: Wu Zhangjin <wuzj@xxxxxxxxxx>
---
arch/mips/Kconfig | 1 +
arch/mips/kernel/ftrace.c | 66 ++++++++++++++++++++++++++++++++++++++++
arch/mips/kernel/mcount.S | 61 +++++++++++++++++++++++++++++++++++--
arch/mips/kernel/vmlinux.lds.S | 1 +
4 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 0857239..5ac9f45 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -9,6 +9,7 @@ config MIPS
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
+ select HAVE_FUNCTION_GRAPH_TRACER
# Horrible source of confusion. Die, die, die ...
select EMBEDDED
select RTC_LIB
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index ad490cc..65d4d56 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -205,3 +205,69 @@ int __init ftrace_dyn_arch_init(void *data)
return 0;
}
#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+#define JMP 0x08000000 /* jump to target directly */
+extern void ftrace_graph_call(void);
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ unsigned long ip = (unsigned long) (&ftrace_graph_call);
+ unsigned char old[MCOUNT_INSN_SIZE], *new;
+ int ret;
+
+ /* j ftrace_stub */
+ memcpy(old, (unsigned long *) ip, MCOUNT_INSN_SIZE);
+ new = ftrace_call_replace(JMP, (unsigned long) ftrace_graph_caller);
+
+ ret = ftrace_modify_code(ip, old, new);
+
+ return ret;
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ unsigned long ip = (unsigned long) (&ftrace_graph_call);
+ unsigned char old[MCOUNT_INSN_SIZE], *new;
+ int ret;
+
+ /* j ftrace_graph_caller */
+ memcpy(old, (unsigned long *) ip, MCOUNT_INSN_SIZE);
+ new = ftrace_call_replace(JMP, (unsigned long) ftrace_stub);
+
+ ret = ftrace_modify_code(ip, old, new);
+
+ return ret;
+}
+
+#endif /* !CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+
+unsigned long prepare_ftrace_return(unsigned long ip,
+ unsigned long parent_ip)
+{
+ struct ftrace_graph_ent trace;
+
+ /* Nmi's are currently unsupported */
+ if (unlikely(in_nmi()) ||
+ unlikely(atomic_read(&current->tracing_graph_pause)) ||
+ (ftrace_push_return_trace(parent_ip, ip, &trace.depth) == -EBUSY))
+ return parent_ip;
+
+ trace.func = ip;
+
+ /* Only trace if the calling function expects to */
+ if (ftrace_graph_entry(&trace))
+ return (unsigned long) &return_to_handler;
+
+ current->curr_ret_stack--;
+ return parent_ip;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
index 723ace2..559f9bd 100644
--- a/arch/mips/kernel/mcount.S
+++ b/arch/mips/kernel/mcount.S
@@ -27,7 +27,6 @@
.macro MCOUNT_SAVE_REGS
PTR_SUBU sp, PT_SIZE
PTR_S ra, PT_R31(sp)
- PTR_S $1, PT_R1(sp)
PTR_S a0, PT_R4(sp)
PTR_S a1, PT_R5(sp)
PTR_S a2, PT_R6(sp)
@@ -42,7 +41,6 @@

.macro MCOUNT_RESTORE_REGS
PTR_L ra, PT_R31(sp)
- PTR_L $1, PT_R1(sp)
PTR_L a0, PT_R4(sp)
PTR_L a1, PT_R5(sp)
PTR_L a2, PT_R6(sp)
@@ -81,6 +79,7 @@ NESTED(ftrace_caller, PT_SIZE, ra)
nop

MCOUNT_SAVE_REGS
+ PTR_S $1, PT_R1(sp)

MCOUNT_SET_ARGS
.globl ftrace_call
@@ -88,7 +87,16 @@ ftrace_call:
jal ftrace_stub
nop

+ PTR_L $1, PT_R1(sp)
MCOUNT_RESTORE_REGS
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ .globl ftrace_graph_call
+ftrace_graph_call:
+ j ftrace_stub
+ nop
+#endif
+
.globl ftrace_stub
ftrace_stub:
RETURN_BACK
@@ -106,17 +114,27 @@ NESTED(_mcount, PT_SIZE, ra)
PTR_L t1, ftrace_trace_function /* please don't use t1 later, safe? */
bne t0, t1, static_trace
nop
-
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ PTR_L t2, ftrace_graph_return
+ bne t0, t2, ftrace_graph_caller
+ nop
+ PTR_LA t0, ftrace_graph_entry_stub
+ PTR_L t2, ftrace_graph_entry
+ bne t0, t2, ftrace_graph_caller
+ nop
+#endif
j ftrace_stub
nop

static_trace:
MCOUNT_SAVE_REGS
+ PTR_S $1, PT_R1(sp)

MCOUNT_SET_ARGS /* call *ftrace_trace_function */
jalr t1
nop

+ PTR_L $1, PT_R1(sp)
MCOUNT_RESTORE_REGS
.globl ftrace_stub
ftrace_stub:
@@ -125,5 +143,42 @@ ftrace_stub:

#endif /* ! CONFIG_DYNAMIC_FTRACE */

+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+NESTED(ftrace_graph_caller, PT_SIZE, ra)
+ MCOUNT_SAVE_REGS
+ PTR_S v0, PT_R2(sp)
+
+ MCOUNT_SET_ARGS
+ jal prepare_ftrace_return
+ nop
+
+ /* overwrite the parent as &return_to_handler: v0 -> $1(at) */
+ move $1, v0
+
+ PTR_L v0, PT_R2(sp)
+ MCOUNT_RESTORE_REGS
+ RETURN_BACK
+ END(ftrace_graph_caller)
+
+ .align 2
+ .globl return_to_handler
+return_to_handler:
+ PTR_SUBU sp, PT_SIZE
+ PTR_S v0, PT_R2(sp)
+
+ jal ftrace_return_to_handler
+ nop
+
+ /* restore the real parent address: v0 -> ra */
+ move ra, v0
+
+ PTR_L v0, PT_R2(sp)
+ PTR_ADDIU sp, PT_SIZE
+
+ jr ra
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
.set at
.set reorder
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 58738c8..67435e5 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -36,6 +36,7 @@ SECTIONS
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
+ IRQENTRY_TEXT
*(.text.*)
*(.fixup)
*(.gnu.warning)
--
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/