diff options
author | Wu Zhangjin <wuzhangjin@gmail.com> | 2009-11-20 20:34:34 +0800 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-12-17 01:57:25 +0000 |
commit | 29c5d3462f7c8f17bb9e0a29f0a299036468074d (patch) | |
tree | ea18e1a1011e27095b1f2b7b68f26e28573d47eb /arch/mips/kernel/mcount.S | |
parent | 8f99a162653531ef25a3dd0f92bfb6332cd2b295 (diff) |
MIPS: Tracing: Add function graph tracer support for MIPS
The implementation of function graph tracer for MIPS is a little
different from X86.
in MIPS, gcc(with -pg) only transfer the caller's return address(at) and
the _mcount's return address(ra) to us.
For the kernel part without -mlong-calls:
move at, ra
jal _mcount
For the module part with -mlong-calls:
lui v1, hi16bit_of_mcount
addiu v1, v1, low16bit_of_mcount
move at, ra
jal _mcount
Without -mlong-calls,
if the function is a leaf, it will not save the return address(ra):
ffffffff80101298 <au1k_wait>:
ffffffff80101298: 67bdfff0 daddiu sp,sp,-16
ffffffff8010129c: ffbe0008 sd s8,8(sp)
ffffffff801012a0: 03a0f02d move s8,sp
ffffffff801012a4: 03e0082d move at,ra
ffffffff801012a8: 0c042930 jal ffffffff8010a4c0 <_mcount>
ffffffff801012ac: 00020021 nop
so, we can hijack it directly in _mcount, but if the function is non-leaf, the
return address is saved in the stack.
ffffffff80133030 <copy_process>:
ffffffff80133030: 67bdff50 daddiu sp,sp,-176
ffffffff80133034: ffbe00a0 sd s8,160(sp)
ffffffff80133038: 03a0f02d move s8,sp
ffffffff8013303c: ffbf00a8 sd ra,168(sp)
ffffffff80133040: ffb70098 sd s7,152(sp)
ffffffff80133044: ffb60090 sd s6,144(sp)
ffffffff80133048: ffb50088 sd s5,136(sp)
ffffffff8013304c: ffb40080 sd s4,128(sp)
ffffffff80133050: ffb30078 sd s3,120(sp)
ffffffff80133054: ffb20070 sd s2,112(sp)
ffffffff80133058: ffb10068 sd s1,104(sp)
ffffffff8013305c: ffb00060 sd s0,96(sp)
ffffffff80133060: 03e0082d move at,ra
ffffffff80133064: 0c042930 jal ffffffff8010a4c0 <_mcount>
ffffffff80133068: 00020021 nop
but we can not get the exact stack address(which saved ra) directly in
_mcount, we need to search the content of at register in the stack space
or search the "s{d,w} ra, offset(sp)" instruction in the text. 'Cause we
can not prove there is only a match in the stack space, so, we search
the text instead.
as we can see, if the first instruction above "move at, ra" is not a
store instruction, there should be a leaf function, so we hijack the at
register directly via putting &return_to_handler into it, otherwise, we
search the "s{d,w} ra, offset(sp)" instruction to get the stack offset,
and then the stack address. we use the above copy_process() as an
example, we at last find "ffbf00a8", 0xa8 is the stack offset, we plus
it with s8(fp), that is the stack address, we hijack the content via
writing the &return_to_handler in.
If with -mlong-calls, since there are two more instructions above "move
at, ra", so, we can move the pointer to the position above "lui v1,
hi16bit_of_mcount".
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Nicholas Mc Guire <der.herr@hofr.at>
Cc: zhangfx@lemote.com
Cc: Wu Zhangjin <wuzhangjin@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/677/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/mcount.S')
-rw-r--r-- | arch/mips/kernel/mcount.S | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index ffc425979d4f..b50e38d828c4 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -93,6 +93,16 @@ NESTED(_mcount, PT_SIZE, ra) PTR_L t1, ftrace_trace_function /* Prepare t1 for (1) */ 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 b ftrace_stub nop @@ -111,5 +121,37 @@ ftrace_stub: #endif /* ! CONFIG_DYNAMIC_FTRACE */ +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +NESTED(ftrace_graph_caller, PT_SIZE, ra) + MCOUNT_SAVE_REGS + + PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */ + move a1, ra /* arg2: next ip, selfaddr */ + jal prepare_ftrace_return + move a2, fp /* arg3: frame pointer */ + + 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 + PTR_S v1, PT_R3(sp) + + /* restore the real parent address: v0 -> ra */ + move ra, v0 + + PTR_L v0, PT_R2(sp) + PTR_L v1, PT_R3(sp) + jr ra + PTR_ADDIU sp, PT_SIZE +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + .set at .set reorder |