diff options
author | Wu Zhangjin <wuzhangjin@gmail.com> | 2009-11-20 07:34:34 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-12-16 20:57:25 -0500 |
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) | |||
93 | PTR_L t1, ftrace_trace_function /* Prepare t1 for (1) */ | 93 | PTR_L t1, ftrace_trace_function /* Prepare t1 for (1) */ |
94 | bne t0, t1, static_trace | 94 | bne t0, t1, static_trace |
95 | nop | 95 | nop |
96 | |||
97 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
98 | PTR_L t2, ftrace_graph_return | ||
99 | bne t0, t2, ftrace_graph_caller | ||
100 | nop | ||
101 | PTR_LA t0, ftrace_graph_entry_stub | ||
102 | PTR_L t2, ftrace_graph_entry | ||
103 | bne t0, t2, ftrace_graph_caller | ||
104 | nop | ||
105 | #endif | ||
96 | b ftrace_stub | 106 | b ftrace_stub |
97 | nop | 107 | nop |
98 | 108 | ||
@@ -111,5 +121,37 @@ ftrace_stub: | |||
111 | 121 | ||
112 | #endif /* ! CONFIG_DYNAMIC_FTRACE */ | 122 | #endif /* ! CONFIG_DYNAMIC_FTRACE */ |
113 | 123 | ||
124 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
125 | |||
126 | NESTED(ftrace_graph_caller, PT_SIZE, ra) | ||
127 | MCOUNT_SAVE_REGS | ||
128 | |||
129 | PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */ | ||
130 | move a1, ra /* arg2: next ip, selfaddr */ | ||
131 | jal prepare_ftrace_return | ||
132 | move a2, fp /* arg3: frame pointer */ | ||
133 | |||
134 | MCOUNT_RESTORE_REGS | ||
135 | RETURN_BACK | ||
136 | END(ftrace_graph_caller) | ||
137 | |||
138 | .align 2 | ||
139 | .globl return_to_handler | ||
140 | return_to_handler: | ||
141 | PTR_SUBU sp, PT_SIZE | ||
142 | PTR_S v0, PT_R2(sp) | ||
143 | |||
144 | jal ftrace_return_to_handler | ||
145 | PTR_S v1, PT_R3(sp) | ||
146 | |||
147 | /* restore the real parent address: v0 -> ra */ | ||
148 | move ra, v0 | ||
149 | |||
150 | PTR_L v0, PT_R2(sp) | ||
151 | PTR_L v1, PT_R3(sp) | ||
152 | jr ra | ||
153 | PTR_ADDIU sp, PT_SIZE | ||
154 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
155 | |||
114 | .set at | 156 | .set at |
115 | .set reorder | 157 | .set reorder |