Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Wu Zhangjin and committed by
Ralf Baechle
7326c4e5 fc49a3be

+38 -7
+7
arch/mips/Makefile
··· 51 51 ifndef CONFIG_FUNCTION_TRACER 52 52 cflags-y := -ffunction-sections 53 53 endif 54 + ifdef CONFIG_FUNCTION_GRAPH_TRACER 55 + ifndef KBUILD_MCOUNT_RA_ADDRESS 56 + ifeq ($(call cc-option-yn,-mmcount-ra-address), y) 57 + cflags-y += -mmcount-ra-address -DKBUILD_MCOUNT_RA_ADDRESS 58 + endif 59 + endif 60 + endif 54 61 cflags-y += $(call cc-option, -mno-check-zero-division) 55 62 56 63 ifdef CONFIG_32BIT
+17 -7
arch/mips/kernel/ftrace.c
··· 148 148 149 149 #endif /* !CONFIG_DYNAMIC_FTRACE */ 150 150 151 + #ifndef KBUILD_MCOUNT_RA_ADDRESS 151 152 #define S_RA_SP (0xafbf << 16) /* s{d,w} ra, offset(sp) */ 152 153 #define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */ 153 154 #define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */ ··· 202 201 return 0; 203 202 } 204 203 204 + #endif 205 + 205 206 /* 206 207 * Hook the return address and push it in the stack of return addrs 207 208 * in current thread info. ··· 221 218 return; 222 219 223 220 /* "parent" is the stack address saved the return address of the caller 224 - * of _mcount, for a leaf function not save the return address in the 225 - * stack address, so, we "emulate" one in _mcount's stack space, and 226 - * hijack it directly, but for a non-leaf function, it will save the 227 - * return address to the its stack space, so, we can not hijack the 228 - * "parent" directly, but need to find the real stack address, 221 + * of _mcount. 222 + * 223 + * if the gcc < 4.5, a leaf function does not save the return address 224 + * in the stack address, so, we "emulate" one in _mcount's stack space, 225 + * and hijack it directly, but for a non-leaf function, it save the 226 + * return address to the its own stack space, we can not hijack it 227 + * directly, but need to find the real stack address, 229 228 * ftrace_get_parent_addr() does it! 229 + * 230 + * if gcc>= 4.5, with the new -mmcount-ra-address option, for a 231 + * non-leaf function, the location of the return address will be saved 232 + * to $12 for us, and for a leaf function, only put a zero into $12. we 233 + * do it in ftrace_graph_caller of mcount.S. 230 234 */ 231 235 232 236 /* old = *parent; */ 233 237 safe_load_stack(old, parent, faulted); 234 238 if (unlikely(faulted)) 235 239 goto out; 236 - 240 + #ifndef KBUILD_MCOUNT_RA_ADDRESS 237 241 parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old, 238 242 (unsigned long)parent, 239 243 fp); ··· 248 238 * ra, stop function graph tracer and return */ 249 239 if (parent == 0) 250 240 goto out; 251 - 241 + #endif 252 242 /* *parent = return_hooker; */ 253 243 safe_store_stack(return_hooker, parent, faulted); 254 244 if (unlikely(faulted))
+14
arch/mips/kernel/mcount.S
··· 70 70 nop 71 71 72 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 77 move a0, ra /* arg1: next ip, selfaddr */ 75 78 .globl ftrace_call ··· 136 133 NESTED(ftrace_graph_caller, PT_SIZE, ra) 137 134 #ifdef CONFIG_DYNAMIC_FTRACE 138 135 PTR_L a1, PT_R31(sp) /* load the original ra from the stack */ 136 + #ifdef KBUILD_MCOUNT_RA_ADDRESS 137 + PTR_L t0, PT_R12(sp) /* load the original t0 from the stack */ 138 + #endif 139 139 #else 140 140 MCOUNT_SAVE_REGS 141 141 move a1, ra /* arg2: next ip, selfaddr */ 142 142 #endif 143 + 144 + #ifdef KBUILD_MCOUNT_RA_ADDRESS 145 + bnez t0, 1f /* non-leaf func: t0 saved the location of the return address */ 146 + nop 147 + PTR_LA t0, PT_R1(sp) /* leaf func: get the location of at(old ra) from our own stack */ 148 + 1: move a0, t0 /* arg1: the location of the return address */ 149 + #else 143 150 PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */ 151 + #endif 144 152 jal prepare_ftrace_return 145 153 #ifdef CONFIG_FRAME_POINTER 146 154 move a2, fp /* arg3: frame pointer */