aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorWu Zhangjin <wuzhangjin@gmail.com>2009-11-20 07:34:38 -0500
committerRalf Baechle <ralf@linux-mips.org>2009-12-16 20:57:27 -0500
commit7326c4e567b50e689d13c04d58aeffa515277ebb (patch)
treeab3ecf92cf84decb1ff7b419920222770024125b /arch/mips/kernel
parentfc49a3be2be7a0cd44fcd3b37557d6d92cae59b1 (diff)
MIPS: Tracing: Make function graph tracer work with -mmcount-ra-address
That thread "MIPS: Add option to pass return address location to _mcount" from "David Daney <ddaney@caviumnetworks.com>" have added a new option -mmcount-ra-address to gcc(4.5) for MIPS to transfer the location of the return address to _mcount. Benefit from this new feature, function graph tracer on MIPS will be easier and safer to hijack the return address of the kernel function, which will save some overhead and make the whole thing more reliable. In this patch, at first, try to enable the option -mmcount-ra-address in arch/mips/Makefile with cc-option, if gcc support it, it will be enabled, otherwise, no side effect. and then, we need to support this new option of gcc 4.5 and also support the old gcc versions. with _mcount in the old gcc versions, it's not easy to get the location of return address(tracing: add function graph tracer support for MIPS), so, we do it in a C function: ftrace_get_parent_addr(ftrace.c), but with -mmcount-ra-address, only several instructions need to get what we want, so, I put into asm(mcount.S). and also, as the $12(t0) is used by -mmcount-ra-address for transferring the localtion of return address to _mcount, we need to save it into the stack and restore it when enabled dynamic function tracer, 'Cause we have called "ftrace_call" before "ftrace_graph_caller", which may destroy $12(t0). (Thanks to David for providing that -mcount-ra-address and giving the idea of KBUILD_MCOUNT_RA_ADDRESS, both of them have made the whole thing more beautiful!) 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/681/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/ftrace.c24
-rw-r--r--arch/mips/kernel/mcount.S14
2 files changed, 31 insertions, 7 deletions
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index e363fc69aabd..68b067040d8b 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -148,6 +148,7 @@ int ftrace_disable_ftrace_graph_caller(void)
148 148
149#endif /* !CONFIG_DYNAMIC_FTRACE */ 149#endif /* !CONFIG_DYNAMIC_FTRACE */
150 150
151#ifndef KBUILD_MCOUNT_RA_ADDRESS
151#define S_RA_SP (0xafbf << 16) /* s{d,w} ra, offset(sp) */ 152#define S_RA_SP (0xafbf << 16) /* s{d,w} ra, offset(sp) */
152#define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */ 153#define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */
153#define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */ 154#define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */
@@ -201,6 +202,8 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
201 return 0; 202 return 0;
202} 203}
203 204
205#endif
206
204/* 207/*
205 * Hook the return address and push it in the stack of return addrs 208 * Hook the return address and push it in the stack of return addrs
206 * in current thread info. 209 * in current thread info.
@@ -218,19 +221,26 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
218 return; 221 return;
219 222
220 /* "parent" is the stack address saved the return address of the caller 223 /* "parent" is the stack address saved the return address of the caller
221 * of _mcount, for a leaf function not save the return address in the 224 * of _mcount.
222 * stack address, so, we "emulate" one in _mcount's stack space, and 225 *
223 * hijack it directly, but for a non-leaf function, it will save the 226 * if the gcc < 4.5, a leaf function does not save the return address
224 * return address to the its stack space, so, we can not hijack the 227 * in the stack address, so, we "emulate" one in _mcount's stack space,
225 * "parent" directly, but need to find the real stack address, 228 * and hijack it directly, but for a non-leaf function, it save the
229 * return address to the its own stack space, we can not hijack it
230 * directly, but need to find the real stack address,
226 * ftrace_get_parent_addr() does it! 231 * ftrace_get_parent_addr() does it!
232 *
233 * if gcc>= 4.5, with the new -mmcount-ra-address option, for a
234 * non-leaf function, the location of the return address will be saved
235 * to $12 for us, and for a leaf function, only put a zero into $12. we
236 * do it in ftrace_graph_caller of mcount.S.
227 */ 237 */
228 238
229 /* old = *parent; */ 239 /* old = *parent; */
230 safe_load_stack(old, parent, faulted); 240 safe_load_stack(old, parent, faulted);
231 if (unlikely(faulted)) 241 if (unlikely(faulted))
232 goto out; 242 goto out;
233 243#ifndef KBUILD_MCOUNT_RA_ADDRESS
234 parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old, 244 parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old,
235 (unsigned long)parent, 245 (unsigned long)parent,
236 fp); 246 fp);
@@ -238,7 +248,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
238 * ra, stop function graph tracer and return */ 248 * ra, stop function graph tracer and return */
239 if (parent == 0) 249 if (parent == 0)
240 goto out; 250 goto out;
241 251#endif
242 /* *parent = return_hooker; */ 252 /* *parent = return_hooker; */
243 safe_store_stack(return_hooker, parent, faulted); 253 safe_store_stack(return_hooker, parent, faulted);
244 if (unlikely(faulted)) 254 if (unlikely(faulted))
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
index 522e91c688fc..0a9cfdb271dd 100644
--- a/arch/mips/kernel/mcount.S
+++ b/arch/mips/kernel/mcount.S
@@ -70,6 +70,9 @@ _mcount:
70 nop 70 nop
71 71
72 MCOUNT_SAVE_REGS 72 MCOUNT_SAVE_REGS
73#ifdef KBUILD_MCOUNT_RA_ADDRESS
74 PTR_S t0, PT_R12(sp) /* t0 saved the location of the return address(at) by -mmcount-ra-address */
75#endif
73 76
74 move a0, ra /* arg1: next ip, selfaddr */ 77 move a0, ra /* arg1: next ip, selfaddr */
75 .globl ftrace_call 78 .globl ftrace_call
@@ -133,11 +136,22 @@ ftrace_stub:
133NESTED(ftrace_graph_caller, PT_SIZE, ra) 136NESTED(ftrace_graph_caller, PT_SIZE, ra)
134#ifdef CONFIG_DYNAMIC_FTRACE 137#ifdef CONFIG_DYNAMIC_FTRACE
135 PTR_L a1, PT_R31(sp) /* load the original ra from the stack */ 138 PTR_L a1, PT_R31(sp) /* load the original ra from the stack */
139#ifdef KBUILD_MCOUNT_RA_ADDRESS
140 PTR_L t0, PT_R12(sp) /* load the original t0 from the stack */
141#endif
136#else 142#else
137 MCOUNT_SAVE_REGS 143 MCOUNT_SAVE_REGS
138 move a1, ra /* arg2: next ip, selfaddr */ 144 move a1, ra /* arg2: next ip, selfaddr */
139#endif 145#endif
146
147#ifdef KBUILD_MCOUNT_RA_ADDRESS
148 bnez t0, 1f /* non-leaf func: t0 saved the location of the return address */
149 nop
150 PTR_LA t0, PT_R1(sp) /* leaf func: get the location of at(old ra) from our own stack */
1511: move a0, t0 /* arg1: the location of the return address */
152#else
140 PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */ 153 PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */
154#endif
141 jal prepare_ftrace_return 155 jal prepare_ftrace_return
142#ifdef CONFIG_FRAME_POINTER 156#ifdef CONFIG_FRAME_POINTER
143 move a2, fp /* arg3: frame pointer */ 157 move a2, fp /* arg3: frame pointer */