• Wu Zhangjin's avatar
    MIPS: Tracing: Add dynamic function tracer support · 538f1952
    Wu Zhangjin authored
    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: default avatarWu 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: default avatarSteven Rostedt <rostedt@goodmis.org>
    Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
    538f1952
recordmcount.pl 17.1 KB