linux/arch/mips/kernel/mcount.S

190 lines
3.8 KiB
ArmAsm
Raw Normal View History

/*
* MIPS specific _mcount support
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive for
* more details.
*
* Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
* Author: Wu Zhangjin <wuzj@lemote.com>
*/
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/ftrace.h>
.text
.set noreorder
.set noat
.macro MCOUNT_SAVE_REGS
PTR_SUBU sp, PT_SIZE
PTR_S ra, PT_R31(sp)
PTR_S AT, PT_R1(sp)
PTR_S a0, PT_R4(sp)
PTR_S a1, PT_R5(sp)
PTR_S a2, PT_R6(sp)
PTR_S a3, PT_R7(sp)
#ifdef CONFIG_64BIT
PTR_S a4, PT_R8(sp)
PTR_S a5, PT_R9(sp)
PTR_S a6, PT_R10(sp)
PTR_S a7, PT_R11(sp)
#endif
.endm
.macro MCOUNT_RESTORE_REGS
PTR_L ra, PT_R31(sp)
PTR_L AT, PT_R1(sp)
PTR_L a0, PT_R4(sp)
PTR_L a1, PT_R5(sp)
PTR_L a2, PT_R6(sp)
PTR_L a3, PT_R7(sp)
#ifdef CONFIG_64BIT
PTR_L a4, PT_R8(sp)
PTR_L a5, PT_R9(sp)
PTR_L a6, PT_R10(sp)
PTR_L a7, PT_R11(sp)
#endif
#ifdef CONFIG_64BIT
PTR_ADDIU sp, PT_SIZE
#else
PTR_ADDIU sp, (PT_SIZE + 8)
#endif
.endm
.macro RETURN_BACK
jr ra
move ra, AT
.endm
MIPS: Tracing: Add dynamic function tracer support With dynamic function tracer, by default, _mcount is defined as an "empty" function, it returns directly without any more action . When enabling it in user-space, it will jump to a real tracing function(ftrace_caller), and do the real job for us. Differ from the static function tracer, dynamic function tracer provides two functions ftrace_make_call()/ftrace_make_nop() to enable/disable the tracing of some indicated kernel functions(set_ftrace_filter). In the -v4 version, the implementation of this support is basically the same as X86 version does: _mcount is implemented as an empty function and ftrace_caller is implemented as a real tracing function respectively. But in this version, to support module tracing with the help of -mlong-calls in arch/mips/Makefile: MODFLAGS += -mlong-calls. The stuff becomes a little more complex. We need to cope with two different type of calling to _mcount. For the kernel part, the calling to _mcount(result of "objdump -hdr vmlinux"). is like this: 108: 03e0082d move at,ra 10c: 0c000000 jal 0 <fpcsr_pending> 10c: R_MIPS_26 _mcount 10c: R_MIPS_NONE *ABS* 10c: R_MIPS_NONE *ABS* 110: 00020021 nop For the module with -mlong-calls, it looks like this: c: 3c030000 lui v1,0x0 c: R_MIPS_HI16 _mcount c: R_MIPS_NONE *ABS* c: R_MIPS_NONE *ABS* 10: 64630000 daddiu v1,v1,0 10: R_MIPS_LO16 _mcount 10: R_MIPS_NONE *ABS* 10: R_MIPS_NONE *ABS* 14: 03e0082d move at,ra 18: 0060f809 jalr v1 In the kernel version, there is only one "_mcount" string for every kernel function, so, we just need to match this one in mcount_regex of scripts/recordmcount.pl, but in the module version, we need to choose one of the two to match. Herein, I choose the first one with "R_MIPS_HI16 _mcount". and In the kernel verion, without module tracing support, we just need to replace "jal _mcount" by "jal ftrace_caller" to do real tracing, and filter the tracing of some kernel functions via replacing it by a nop instruction. but as we have described before, the instruction "jal ftrace_caller" only left 32bit length for the address of ftrace_caller, it will fail when calling from the module space. so, herein, we must replace something else. the basic idea is loading the address of ftrace_caller to v1 via changing these two instructions: lui v1,0x0 addiu v1,v1,0 If we want to enable the tracing, we need to replace the above instructions to: lui v1, HI_16BIT_ftrace_caller addiu v1, v1, LOW_16BIT_ftrace_caller If we want to stop the tracing of the indicated kernel functions, we just need to replace the "jalr v1" to a nop instruction. but we need to replace two instructions and encode the above two instructions oursevles. Is there a simpler solution? Yes! Here it is, in this version, we put _mcount and ftrace_caller together, which means the address of _mcount and ftrace_caller is the same: _mcount: ftrace_caller: j ftrace_stub nop ...(do real tracing here)... ftrace_stub: jr ra move ra, at By default, the kernel functions call _mcount, and then jump to ftrace_stub and return. and when we want to do real tracing, we just need to remove that "j ftrace_stub", and it will run through the two "nop" instructions and then do the real tracing job. what about filtering job? we just need to do this: lui v1, hi_16bit_of_mcount <--> b 1f (0x10000004) addiu v1, v1, low_16bit_of_mcount move at, ra jalr v1 nop 1f: (rec->ip + 12) In linux-mips64, there will be some local symbols, whose name are prefixed by $L, which need to be filtered. thanks goes to Steven for writing the mips64-specific function_regex. In a conclusion, with RISC, things becomes easier with such a "stupid" trick, RISC is something like K.I.S.S, and also, there are lots of "simple" tricks in the whole ftrace support, thanks goes to Steven and the other folks for providing such a wonderful tracing framework! Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> 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/675/ Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2009-11-20 12:34:32 +00:00
#ifdef CONFIG_DYNAMIC_FTRACE
NESTED(ftrace_caller, PT_SIZE, ra)
.globl _mcount
_mcount:
b ftrace_stub
nop
lw t1, function_trace_stop
bnez t1, ftrace_stub
MIPS: Tracing: Add dynamic function tracer support With dynamic function tracer, by default, _mcount is defined as an "empty" function, it returns directly without any more action . When enabling it in user-space, it will jump to a real tracing function(ftrace_caller), and do the real job for us. Differ from the static function tracer, dynamic function tracer provides two functions ftrace_make_call()/ftrace_make_nop() to enable/disable the tracing of some indicated kernel functions(set_ftrace_filter). In the -v4 version, the implementation of this support is basically the same as X86 version does: _mcount is implemented as an empty function and ftrace_caller is implemented as a real tracing function respectively. But in this version, to support module tracing with the help of -mlong-calls in arch/mips/Makefile: MODFLAGS += -mlong-calls. The stuff becomes a little more complex. We need to cope with two different type of calling to _mcount. For the kernel part, the calling to _mcount(result of "objdump -hdr vmlinux"). is like this: 108: 03e0082d move at,ra 10c: 0c000000 jal 0 <fpcsr_pending> 10c: R_MIPS_26 _mcount 10c: R_MIPS_NONE *ABS* 10c: R_MIPS_NONE *ABS* 110: 00020021 nop For the module with -mlong-calls, it looks like this: c: 3c030000 lui v1,0x0 c: R_MIPS_HI16 _mcount c: R_MIPS_NONE *ABS* c: R_MIPS_NONE *ABS* 10: 64630000 daddiu v1,v1,0 10: R_MIPS_LO16 _mcount 10: R_MIPS_NONE *ABS* 10: R_MIPS_NONE *ABS* 14: 03e0082d move at,ra 18: 0060f809 jalr v1 In the kernel version, there is only one "_mcount" string for every kernel function, so, we just need to match this one in mcount_regex of scripts/recordmcount.pl, but in the module version, we need to choose one of the two to match. Herein, I choose the first one with "R_MIPS_HI16 _mcount". and In the kernel verion, without module tracing support, we just need to replace "jal _mcount" by "jal ftrace_caller" to do real tracing, and filter the tracing of some kernel functions via replacing it by a nop instruction. but as we have described before, the instruction "jal ftrace_caller" only left 32bit length for the address of ftrace_caller, it will fail when calling from the module space. so, herein, we must replace something else. the basic idea is loading the address of ftrace_caller to v1 via changing these two instructions: lui v1,0x0 addiu v1,v1,0 If we want to enable the tracing, we need to replace the above instructions to: lui v1, HI_16BIT_ftrace_caller addiu v1, v1, LOW_16BIT_ftrace_caller If we want to stop the tracing of the indicated kernel functions, we just need to replace the "jalr v1" to a nop instruction. but we need to replace two instructions and encode the above two instructions oursevles. Is there a simpler solution? Yes! Here it is, in this version, we put _mcount and ftrace_caller together, which means the address of _mcount and ftrace_caller is the same: _mcount: ftrace_caller: j ftrace_stub nop ...(do real tracing here)... ftrace_stub: jr ra move ra, at By default, the kernel functions call _mcount, and then jump to ftrace_stub and return. and when we want to do real tracing, we just need to remove that "j ftrace_stub", and it will run through the two "nop" instructions and then do the real tracing job. what about filtering job? we just need to do this: lui v1, hi_16bit_of_mcount <--> b 1f (0x10000004) addiu v1, v1, low_16bit_of_mcount move at, ra jalr v1 nop 1f: (rec->ip + 12) In linux-mips64, there will be some local symbols, whose name are prefixed by $L, which need to be filtered. thanks goes to Steven for writing the mips64-specific function_regex. In a conclusion, with RISC, things becomes easier with such a "stupid" trick, RISC is something like K.I.S.S, and also, there are lots of "simple" tricks in the whole ftrace support, thanks goes to Steven and the other folks for providing such a wonderful tracing framework! Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> 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/675/ Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2009-11-20 12:34:32 +00:00
nop
MCOUNT_SAVE_REGS
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>
2009-11-20 12:34:38 +00:00
#ifdef KBUILD_MCOUNT_RA_ADDRESS
PTR_S t0, PT_R12(sp) /* t0 saved the location of the return address(at) by -mmcount-ra-address */
#endif
MIPS: Tracing: Add dynamic function tracer support With dynamic function tracer, by default, _mcount is defined as an "empty" function, it returns directly without any more action . When enabling it in user-space, it will jump to a real tracing function(ftrace_caller), and do the real job for us. Differ from the static function tracer, dynamic function tracer provides two functions ftrace_make_call()/ftrace_make_nop() to enable/disable the tracing of some indicated kernel functions(set_ftrace_filter). In the -v4 version, the implementation of this support is basically the same as X86 version does: _mcount is implemented as an empty function and ftrace_caller is implemented as a real tracing function respectively. But in this version, to support module tracing with the help of -mlong-calls in arch/mips/Makefile: MODFLAGS += -mlong-calls. The stuff becomes a little more complex. We need to cope with two different type of calling to _mcount. For the kernel part, the calling to _mcount(result of "objdump -hdr vmlinux"). is like this: 108: 03e0082d move at,ra 10c: 0c000000 jal 0 <fpcsr_pending> 10c: R_MIPS_26 _mcount 10c: R_MIPS_NONE *ABS* 10c: R_MIPS_NONE *ABS* 110: 00020021 nop For the module with -mlong-calls, it looks like this: c: 3c030000 lui v1,0x0 c: R_MIPS_HI16 _mcount c: R_MIPS_NONE *ABS* c: R_MIPS_NONE *ABS* 10: 64630000 daddiu v1,v1,0 10: R_MIPS_LO16 _mcount 10: R_MIPS_NONE *ABS* 10: R_MIPS_NONE *ABS* 14: 03e0082d move at,ra 18: 0060f809 jalr v1 In the kernel version, there is only one "_mcount" string for every kernel function, so, we just need to match this one in mcount_regex of scripts/recordmcount.pl, but in the module version, we need to choose one of the two to match. Herein, I choose the first one with "R_MIPS_HI16 _mcount". and In the kernel verion, without module tracing support, we just need to replace "jal _mcount" by "jal ftrace_caller" to do real tracing, and filter the tracing of some kernel functions via replacing it by a nop instruction. but as we have described before, the instruction "jal ftrace_caller" only left 32bit length for the address of ftrace_caller, it will fail when calling from the module space. so, herein, we must replace something else. the basic idea is loading the address of ftrace_caller to v1 via changing these two instructions: lui v1,0x0 addiu v1,v1,0 If we want to enable the tracing, we need to replace the above instructions to: lui v1, HI_16BIT_ftrace_caller addiu v1, v1, LOW_16BIT_ftrace_caller If we want to stop the tracing of the indicated kernel functions, we just need to replace the "jalr v1" to a nop instruction. but we need to replace two instructions and encode the above two instructions oursevles. Is there a simpler solution? Yes! Here it is, in this version, we put _mcount and ftrace_caller together, which means the address of _mcount and ftrace_caller is the same: _mcount: ftrace_caller: j ftrace_stub nop ...(do real tracing here)... ftrace_stub: jr ra move ra, at By default, the kernel functions call _mcount, and then jump to ftrace_stub and return. and when we want to do real tracing, we just need to remove that "j ftrace_stub", and it will run through the two "nop" instructions and then do the real tracing job. what about filtering job? we just need to do this: lui v1, hi_16bit_of_mcount <--> b 1f (0x10000004) addiu v1, v1, low_16bit_of_mcount move at, ra jalr v1 nop 1f: (rec->ip + 12) In linux-mips64, there will be some local symbols, whose name are prefixed by $L, which need to be filtered. thanks goes to Steven for writing the mips64-specific function_regex. In a conclusion, with RISC, things becomes easier with such a "stupid" trick, RISC is something like K.I.S.S, and also, there are lots of "simple" tricks in the whole ftrace support, thanks goes to Steven and the other folks for providing such a wonderful tracing framework! Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> 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/675/ Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2009-11-20 12:34:32 +00:00
move a0, ra /* arg1: next ip, selfaddr */
.globl ftrace_call
ftrace_call:
nop /* a placeholder for the call to a real tracing function */
move a1, AT /* arg2: the caller's next ip, parent */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl ftrace_graph_call
ftrace_graph_call:
nop
nop
#endif
MIPS: Tracing: Add dynamic function tracer support With dynamic function tracer, by default, _mcount is defined as an "empty" function, it returns directly without any more action . When enabling it in user-space, it will jump to a real tracing function(ftrace_caller), and do the real job for us. Differ from the static function tracer, dynamic function tracer provides two functions ftrace_make_call()/ftrace_make_nop() to enable/disable the tracing of some indicated kernel functions(set_ftrace_filter). In the -v4 version, the implementation of this support is basically the same as X86 version does: _mcount is implemented as an empty function and ftrace_caller is implemented as a real tracing function respectively. But in this version, to support module tracing with the help of -mlong-calls in arch/mips/Makefile: MODFLAGS += -mlong-calls. The stuff becomes a little more complex. We need to cope with two different type of calling to _mcount. For the kernel part, the calling to _mcount(result of "objdump -hdr vmlinux"). is like this: 108: 03e0082d move at,ra 10c: 0c000000 jal 0 <fpcsr_pending> 10c: R_MIPS_26 _mcount 10c: R_MIPS_NONE *ABS* 10c: R_MIPS_NONE *ABS* 110: 00020021 nop For the module with -mlong-calls, it looks like this: c: 3c030000 lui v1,0x0 c: R_MIPS_HI16 _mcount c: R_MIPS_NONE *ABS* c: R_MIPS_NONE *ABS* 10: 64630000 daddiu v1,v1,0 10: R_MIPS_LO16 _mcount 10: R_MIPS_NONE *ABS* 10: R_MIPS_NONE *ABS* 14: 03e0082d move at,ra 18: 0060f809 jalr v1 In the kernel version, there is only one "_mcount" string for every kernel function, so, we just need to match this one in mcount_regex of scripts/recordmcount.pl, but in the module version, we need to choose one of the two to match. Herein, I choose the first one with "R_MIPS_HI16 _mcount". and In the kernel verion, without module tracing support, we just need to replace "jal _mcount" by "jal ftrace_caller" to do real tracing, and filter the tracing of some kernel functions via replacing it by a nop instruction. but as we have described before, the instruction "jal ftrace_caller" only left 32bit length for the address of ftrace_caller, it will fail when calling from the module space. so, herein, we must replace something else. the basic idea is loading the address of ftrace_caller to v1 via changing these two instructions: lui v1,0x0 addiu v1,v1,0 If we want to enable the tracing, we need to replace the above instructions to: lui v1, HI_16BIT_ftrace_caller addiu v1, v1, LOW_16BIT_ftrace_caller If we want to stop the tracing of the indicated kernel functions, we just need to replace the "jalr v1" to a nop instruction. but we need to replace two instructions and encode the above two instructions oursevles. Is there a simpler solution? Yes! Here it is, in this version, we put _mcount and ftrace_caller together, which means the address of _mcount and ftrace_caller is the same: _mcount: ftrace_caller: j ftrace_stub nop ...(do real tracing here)... ftrace_stub: jr ra move ra, at By default, the kernel functions call _mcount, and then jump to ftrace_stub and return. and when we want to do real tracing, we just need to remove that "j ftrace_stub", and it will run through the two "nop" instructions and then do the real tracing job. what about filtering job? we just need to do this: lui v1, hi_16bit_of_mcount <--> b 1f (0x10000004) addiu v1, v1, low_16bit_of_mcount move at, ra jalr v1 nop 1f: (rec->ip + 12) In linux-mips64, there will be some local symbols, whose name are prefixed by $L, which need to be filtered. thanks goes to Steven for writing the mips64-specific function_regex. In a conclusion, with RISC, things becomes easier with such a "stupid" trick, RISC is something like K.I.S.S, and also, there are lots of "simple" tricks in the whole ftrace support, thanks goes to Steven and the other folks for providing such a wonderful tracing framework! Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> 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/675/ Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2009-11-20 12:34:32 +00:00
MCOUNT_RESTORE_REGS
.globl ftrace_stub
ftrace_stub:
RETURN_BACK
END(ftrace_caller)
#else /* ! CONFIG_DYNAMIC_FTRACE */
NESTED(_mcount, PT_SIZE, ra)
lw t1, function_trace_stop
bnez t1, ftrace_stub
nop
PTR_LA t1, ftrace_stub
PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */
bne t1, t2, static_trace
nop
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>
2009-11-20 12:34:34 +00:00
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
PTR_L t3, ftrace_graph_return
bne t1, t3, ftrace_graph_caller
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>
2009-11-20 12:34:34 +00:00
nop
PTR_LA t1, ftrace_graph_entry_stub
PTR_L t3, ftrace_graph_entry
bne t1, t3, ftrace_graph_caller
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>
2009-11-20 12:34:34 +00:00
nop
#endif
b ftrace_stub
nop
static_trace:
MCOUNT_SAVE_REGS
move a0, ra /* arg1: next ip, selfaddr */
jalr t2 /* (1) call *ftrace_trace_function */
move a1, AT /* arg2: the caller's next ip, parent */
MCOUNT_RESTORE_REGS
.globl ftrace_stub
ftrace_stub:
RETURN_BACK
END(_mcount)
MIPS: Tracing: Add dynamic function tracer support With dynamic function tracer, by default, _mcount is defined as an "empty" function, it returns directly without any more action . When enabling it in user-space, it will jump to a real tracing function(ftrace_caller), and do the real job for us. Differ from the static function tracer, dynamic function tracer provides two functions ftrace_make_call()/ftrace_make_nop() to enable/disable the tracing of some indicated kernel functions(set_ftrace_filter). In the -v4 version, the implementation of this support is basically the same as X86 version does: _mcount is implemented as an empty function and ftrace_caller is implemented as a real tracing function respectively. But in this version, to support module tracing with the help of -mlong-calls in arch/mips/Makefile: MODFLAGS += -mlong-calls. The stuff becomes a little more complex. We need to cope with two different type of calling to _mcount. For the kernel part, the calling to _mcount(result of "objdump -hdr vmlinux"). is like this: 108: 03e0082d move at,ra 10c: 0c000000 jal 0 <fpcsr_pending> 10c: R_MIPS_26 _mcount 10c: R_MIPS_NONE *ABS* 10c: R_MIPS_NONE *ABS* 110: 00020021 nop For the module with -mlong-calls, it looks like this: c: 3c030000 lui v1,0x0 c: R_MIPS_HI16 _mcount c: R_MIPS_NONE *ABS* c: R_MIPS_NONE *ABS* 10: 64630000 daddiu v1,v1,0 10: R_MIPS_LO16 _mcount 10: R_MIPS_NONE *ABS* 10: R_MIPS_NONE *ABS* 14: 03e0082d move at,ra 18: 0060f809 jalr v1 In the kernel version, there is only one "_mcount" string for every kernel function, so, we just need to match this one in mcount_regex of scripts/recordmcount.pl, but in the module version, we need to choose one of the two to match. Herein, I choose the first one with "R_MIPS_HI16 _mcount". and In the kernel verion, without module tracing support, we just need to replace "jal _mcount" by "jal ftrace_caller" to do real tracing, and filter the tracing of some kernel functions via replacing it by a nop instruction. but as we have described before, the instruction "jal ftrace_caller" only left 32bit length for the address of ftrace_caller, it will fail when calling from the module space. so, herein, we must replace something else. the basic idea is loading the address of ftrace_caller to v1 via changing these two instructions: lui v1,0x0 addiu v1,v1,0 If we want to enable the tracing, we need to replace the above instructions to: lui v1, HI_16BIT_ftrace_caller addiu v1, v1, LOW_16BIT_ftrace_caller If we want to stop the tracing of the indicated kernel functions, we just need to replace the "jalr v1" to a nop instruction. but we need to replace two instructions and encode the above two instructions oursevles. Is there a simpler solution? Yes! Here it is, in this version, we put _mcount and ftrace_caller together, which means the address of _mcount and ftrace_caller is the same: _mcount: ftrace_caller: j ftrace_stub nop ...(do real tracing here)... ftrace_stub: jr ra move ra, at By default, the kernel functions call _mcount, and then jump to ftrace_stub and return. and when we want to do real tracing, we just need to remove that "j ftrace_stub", and it will run through the two "nop" instructions and then do the real tracing job. what about filtering job? we just need to do this: lui v1, hi_16bit_of_mcount <--> b 1f (0x10000004) addiu v1, v1, low_16bit_of_mcount move at, ra jalr v1 nop 1f: (rec->ip + 12) In linux-mips64, there will be some local symbols, whose name are prefixed by $L, which need to be filtered. thanks goes to Steven for writing the mips64-specific function_regex. In a conclusion, with RISC, things becomes easier with such a "stupid" trick, RISC is something like K.I.S.S, and also, there are lots of "simple" tricks in the whole ftrace support, thanks goes to Steven and the other folks for providing such a wonderful tracing framework! Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> 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/675/ Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2009-11-20 12:34:32 +00:00
#endif /* ! CONFIG_DYNAMIC_FTRACE */
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>
2009-11-20 12:34:34 +00:00
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
NESTED(ftrace_graph_caller, PT_SIZE, ra)
#ifdef CONFIG_DYNAMIC_FTRACE
PTR_L a1, PT_R31(sp) /* load the original ra from the stack */
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>
2009-11-20 12:34:38 +00:00
#ifdef KBUILD_MCOUNT_RA_ADDRESS
PTR_L t0, PT_R12(sp) /* load the original t0 from the stack */
#endif
#else
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>
2009-11-20 12:34:34 +00:00
MCOUNT_SAVE_REGS
move a1, ra /* arg2: next ip, selfaddr */
#endif
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>
2009-11-20 12:34:38 +00:00
#ifdef KBUILD_MCOUNT_RA_ADDRESS
bnez t0, 1f /* non-leaf func: t0 saved the location of the return address */
nop
PTR_LA t0, PT_R1(sp) /* leaf func: get the location of at(old ra) from our own stack */
1: move a0, t0 /* arg1: the location of the return address */
#else
PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */
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>
2009-11-20 12:34:38 +00:00
#endif
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>
2009-11-20 12:34:34 +00:00
jal prepare_ftrace_return
#ifdef CONFIG_FRAME_POINTER
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>
2009-11-20 12:34:34 +00:00
move a2, fp /* arg3: frame pointer */
#else
#ifdef CONFIG_64BIT
PTR_LA a2, PT_SIZE(sp)
#else
PTR_LA a2, (PT_SIZE+8)(sp)
#endif
#endif
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>
2009-11-20 12:34:34 +00:00
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