From: Wu Zhangjin <wuzhangjin@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org, Thomas Gleixner <tglx@linutronix.de>,
Ralf Baechle <ralf@linux-mips.org>,
Nicholas Mc Guire <der.herr@hofr.at>,
Steven Rostedt <rostedt@goodmis.org>
Subject: Re: [PATCH -v4 9/9] tracing: add function graph tracer support for MIPS
Date: Wed, 21 Oct 2009 23:21:46 +0800 [thread overview]
Message-ID: <1256138506.11274.13.camel@falcon> (raw)
In-Reply-To: <53bdfdd95ec4fa00d4cc505bb5972cf21243a14d.1256135456.git.wuzhangjin@gmail.com>
On Wed, 2009-10-21 at 22:35 +0800, Wu Zhangjin wrote:
> 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.
>
> move at, ra
> jal _mcount
>
> in the function is a leaf, it will no 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 "move s8,
> sp"(move fp, sp), it is a leaf function, so we hijack the at register
> directly via put &return_to_handler into it, and 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.
>
> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
> ---
> arch/mips/Kconfig | 1 +
> arch/mips/kernel/ftrace.c | 192 ++++++++++++++++++++++++++++++++++++++++
> arch/mips/kernel/mcount.S | 55 +++++++++++-
> arch/mips/kernel/vmlinux.lds.S | 1 +
> 4 files changed, 248 insertions(+), 1 deletions(-)
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 147fbbc..de690fd 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -8,6 +8,7 @@ config MIPS
> select HAVE_FUNCTION_TRACE_MCOUNT_TEST
> select HAVE_DYNAMIC_FTRACE
> select HAVE_FTRACE_MCOUNT_RECORD
> + select HAVE_FUNCTION_GRAPH_TRACER
> # Horrible source of confusion. Die, die, die ...
> select EMBEDDED
> select RTC_LIB if !LEMOTE_FULOONG2E
> diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
> index 1e44865..fddee5b 100644
> --- a/arch/mips/kernel/ftrace.c
> +++ b/arch/mips/kernel/ftrace.c
> @@ -13,6 +13,8 @@
> #include <linux/ftrace.h>
>
> #include <asm/cacheflush.h>
> +#include <asm/asm.h>
> +#include <asm/asm-offsets.h>
>
> #ifdef CONFIG_DYNAMIC_FTRACE
>
> @@ -105,3 +107,193 @@ int __init ftrace_dyn_arch_init(void *data)
> return 0;
> }
> #endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +
> +#define JMP 0x08000000 /* jump to target directly */
> +extern void ftrace_graph_call(void);
> +
> +int ftrace_enable_ftrace_graph_caller(void)
> +{
> + unsigned long ip = (unsigned long)(&ftrace_graph_call);
> + unsigned char old[MCOUNT_INSN_SIZE], *new;
> + int ret;
> +
> + /* j ftrace_stub */
> + memcpy(old, (unsigned long *)ip, MCOUNT_INSN_SIZE);
> + new = ftrace_call_replace(JMP, (unsigned long)ftrace_graph_caller);
> +
> + ret = ftrace_modify_code(ip, old, new);
> +
> + return ret;
> +}
> +
> +int ftrace_disable_ftrace_graph_caller(void)
> +{
> + unsigned long ip = (unsigned long)(&ftrace_graph_call);
> + unsigned char old[MCOUNT_INSN_SIZE], *new;
> + int ret;
> +
> + /* j ftrace_graph_caller */
> + memcpy(old, (unsigned long *)ip, MCOUNT_INSN_SIZE);
> + new = ftrace_call_replace(JMP, (unsigned long)ftrace_stub);
> +
> + ret = ftrace_modify_code(ip, old, new);
> +
> + return ret;
> +}
> +
> +#endif /* !CONFIG_DYNAMIC_FTRACE */
> +
> +#define S_RA (0x2fbf << 16) /* 32bit: afbf, 64bit: ffbf */
> +/* This is only available when enabled -fno-omit-frame-pointer with CONFIG_FRAME_POINTER=y */
> +#define MOV_FP_SP 0x03a0f021 /* 32bit: 0x03a0f021, 64bit: 0x03a0f02d */
> +#define STACK_OFFSET_MASK 0xfff /* stack offset range: 0 ~ PT_SIZE(304) */
> +
> +unsigned long ftrace_get_parent_addr(unsigned long self_addr,
> + unsigned long parent,
> + unsigned long parent_addr,
> + unsigned long fp)
> +{
> + unsigned long sp, ip, ra;
> + unsigned int code;
> +
> + /* move to the instruction "move ra, at" */
> + ip = self_addr - 8;
> +
> + /* search the text until finding the "move s8, sp" instruction or
> + * "s{d,w} ra, offset(sp)" instruction */
> + do {
> + ip -= 4;
> + /* read the text we want to match */
> + if (probe_kernel_read(&code, (void *)ip, 4)) {
> + WARN_ON(1);
> + panic("read the text failure\n");
> + }
> +
> + /* if the first instruction above "move at, ra" is "move
> + * s8(fp), sp", means the function is a leaf */
> + if ((code & MOV_FP_SP) == MOV_FP_SP)
> + return parent_addr;
> + } while (((code & S_RA) != S_RA));
> +
> + sp = fp + (code & STACK_OFFSET_MASK);
> + ra = *(unsigned long *)sp;
> +
Seems missed the fault protection here? is there a need? never met fault
in this place and also the following two places, so, are we safe to
remove all of the fault protection?
Regards
Wu Zhangjin
> + if (ra == parent)
> + return sp;
> + else
> + panic
> + ("failed on getting stack address of ra\n: addr: 0x%lx, code: 0x%x\n",
> + ip, code);
> +}
> +
> +/*
> + * Hook the return address and push it in the stack of return addrs
> + * in current thread info.
> + */
> +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
> + unsigned long fp)
> +{
> + unsigned long old;
> + int faulted;
> + struct ftrace_graph_ent trace;
> + unsigned long return_hooker = (unsigned long)
> + &return_to_handler;
> +
> + /*
> + * Protect against fault, even if it shouldn't
> + * happen. This tool is too much intrusive to
> + * ignore such a protection.
> + *
> + * old = *parent;
> + */
> + asm volatile (
> + "1: " STR(PTR_L) " %[old], 0(%[parent])\n"
> + " li %[faulted], 0\n"
> + "2:\n"
> +
> + ".section .fixup, \"ax\"\n"
> + "3: li %[faulted], 1\n"
> + " j 2b\n"
> + ".previous\n"
> +
> + ".section\t__ex_table,\"a\"\n\t"
> + STR(PTR) "\t1b, 3b\n\t"
> + ".previous\n"
> +
> + : [old] "=&r" (old), [faulted] "=r" (faulted)
> + : [parent] "r" (parent)
> + : "memory"
> + );
> +
> + if (unlikely(faulted)) {
> + ftrace_graph_stop();
> + WARN_ON(1);
> + return;
> + }
> +
> + /* The argument *parent only work for leaf function, we need to check
> + * whether the function is leaf, if not, we need to get the real stack
> + * address which stored it.
> + *
> + * and here, we must stop tracing before calling probe_kernel_read().
> + * after calling it, restart tracing. otherwise, it will hang there.*/
> + tracing_stop();
> + parent =
> + (unsigned long *)ftrace_get_parent_addr(self_addr, old,
> + (unsigned long)parent, fp);
> + tracing_start();
> +
> + if (unlikely(atomic_read(¤t->tracing_graph_pause)))
> + return;
> +
> + /*
> + * Protect against fault, even if it shouldn't
> + * happen. This tool is too much intrusive to
> + * ignore such a protection.
> + *
> + * *parent = return_hooker;
> + */
> + asm volatile (
> + "1: " STR(PTR_S) " %[return_hooker], 0(%[parent])\n"
> + " li %[faulted], 0\n"
> + "2:\n"
> +
> + ".section .fixup, \"ax\"\n"
> + "3: li %[faulted], 1\n"
> + " j 2b\n"
> + ".previous\n"
> +
> + ".section\t__ex_table,\"a\"\n\t"
> + STR(PTR) "\t1b, 3b\n\t"
> + ".previous\n"
> +
> + : [faulted] "=r" (faulted)
> + : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
> + : "memory"
> + );
> +
> + if (unlikely(faulted)) {
> + ftrace_graph_stop();
> + WARN_ON(1);
> + return;
> + }
> +
> + if (ftrace_push_return_trace(old, self_addr, &trace.depth, fp) ==
> + -EBUSY) {
> + *parent = old;
> + return;
> + }
> +
> + trace.func = self_addr;
> +
> + /* Only trace if the calling function expects to */
> + if (!ftrace_graph_entry(&trace)) {
> + current->curr_ret_stack--;
> + *parent = old;
> + }
> +}
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
> index 30637e6..356e81c 100644
> --- a/arch/mips/kernel/mcount.S
> +++ b/arch/mips/kernel/mcount.S
> @@ -89,6 +89,14 @@ ftrace_call:
> nop
>
> MCOUNT_RESTORE_REGS
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> + .globl ftrace_graph_call
> +ftrace_graph_call:
> + j ftrace_stub
> + nop
> +#endif
> +
> .globl ftrace_stub
> ftrace_stub:
> RETURN_BACK
> @@ -106,7 +114,15 @@ NESTED(_mcount, PT_SIZE, ra)
> PTR_L t1, ftrace_trace_function /* please don't use t1 later, safe? */
> bne t0, t1, static_trace
> nop
> -
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> + PTR_L t2, ftrace_graph_return
> + bne t0, t2, ftrace_graph_caller
> + nop
> + PTR_LA t0, ftrace_graph_entry_stub
> + PTR_L t2, ftrace_graph_entry
> + bne t0, t2, ftrace_graph_caller
> + nop
> +#endif
> j ftrace_stub
> nop
>
> @@ -125,5 +141,42 @@ ftrace_stub:
>
> #endif /* ! CONFIG_DYNAMIC_FTRACE */
>
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +
> +NESTED(ftrace_graph_caller, PT_SIZE, ra)
> + MCOUNT_SAVE_REGS
> +
> + PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */
> + move a1, ra /* arg2: next ip, selfaddr */
> + PTR_SUBU a1, MCOUNT_INSN_SIZE
> + move a2, fp /* arg3: frame pointer */
> + jal prepare_ftrace_return
> + nop
> +
> + 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)
> + PTR_S v1, PT_R3(sp)
> +
> + jal ftrace_return_to_handler
> + nop
> +
> + /* restore the real parent address: v0 -> ra */
> + move ra, v0
> +
> + PTR_L v0, PT_R2(sp)
> + PTR_L v1, PT_R3(sp)
> + PTR_ADDIU sp, PT_SIZE
> +
> + jr ra
> + nop
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> +
> .set at
> .set reorder
> diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
> index 162b299..f25df73 100644
> --- a/arch/mips/kernel/vmlinux.lds.S
> +++ b/arch/mips/kernel/vmlinux.lds.S
> @@ -46,6 +46,7 @@ SECTIONS
> SCHED_TEXT
> LOCK_TEXT
> KPROBES_TEXT
> + IRQENTRY_TEXT
> *(.text.*)
> *(.fixup)
> *(.gnu.warning)
next prev parent reply other threads:[~2009-10-21 15:22 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1256135456.git.wuzhangjin@gmail.com>
2009-10-21 14:34 ` [PATCH -v4 1/9] tracing: convert trace_clock_local() as weak function Wu Zhangjin
2009-10-21 14:34 ` [PATCH -v4 2/9] MIPS: add mips_timecounter_read() to get high precision timestamp Wu Zhangjin
2009-10-21 14:34 ` [PATCH -v4 3/9] tracing: add MIPS specific trace_clock_local() Wu Zhangjin
2009-10-21 14:46 ` Steven Rostedt
2009-10-21 15:11 ` Wu Zhangjin
2009-10-21 14:34 ` [PATCH -v4 4/9] tracing: add static function tracer support for MIPS Wu Zhangjin
2009-10-21 15:24 ` Steven Rostedt
2009-10-22 17:47 ` Wu Zhangjin
2009-10-22 17:59 ` Steven Rostedt
2009-10-22 18:34 ` Wu Zhangjin
2009-10-22 18:34 ` David Daney
2009-10-22 19:13 ` Wu Zhangjin
[not found] ` <19168.49354.525249.654494@ropi.home>
2009-10-22 20:52 ` Steven Rostedt
2009-10-22 21:09 ` Frederic Weisbecker
2009-10-22 21:29 ` Adam Nemet
2009-10-22 21:55 ` Steven Rostedt
2009-10-23 1:09 ` Wu Zhangjin
2009-10-22 22:17 ` Richard Sandiford
2009-10-23 9:32 ` Wu Zhangjin
2009-10-23 22:48 ` [PATCH] MIPS: Add option to pass return address location to _mcount. Was: " David Daney
2009-10-24 9:12 ` Richard Sandiford
2009-10-24 15:53 ` Wu Zhangjin
2009-10-26 19:08 ` [PATCH] MIPS: Add option to pass return address location to _mcount David Daney
2009-10-27 1:04 ` Wu Zhangjin
2009-10-27 21:20 ` Richard Sandiford
2009-10-29 6:44 ` Wu Zhangjin
2009-10-29 16:32 ` David Daney
2009-10-29 18:11 ` David Daney
2009-10-23 7:21 ` [PATCH -v4 4/9] tracing: add static function tracer support for MIPS Wu Zhangjin
2009-10-21 14:34 ` [PATCH -v4 5/9] tracing: enable HAVE_FUNCTION_TRACE_MCOUNT_TEST " Wu Zhangjin
2009-10-21 14:35 ` [PATCH -v4 6/9] tracing: add an endian argument to scripts/recordmcount.pl Wu Zhangjin
2009-10-21 15:26 ` Steven Rostedt
2009-10-21 14:35 ` [PATCH -v4 7/9] tracing: add dynamic function tracer support for MIPS Wu Zhangjin
2009-10-21 14:35 ` [PATCH -v4 8/9] tracing: not trace mips_timecounter_init() in MIPS Wu Zhangjin
2009-10-21 14:35 ` [PATCH -v4 9/9] tracing: add function graph tracer support for MIPS Wu Zhangjin
2009-10-21 15:21 ` Wu Zhangjin [this message]
2009-10-21 16:14 ` Steven Rostedt
2009-10-21 16:12 ` Steven Rostedt
2009-10-21 16:37 ` David Daney
2009-10-21 16:46 ` Steven Rostedt
2009-10-21 17:07 ` David Daney
2009-10-21 17:23 ` Steven Rostedt
2009-10-21 17:48 ` David Daney
2009-10-21 18:09 ` Steven Rostedt
2009-10-21 18:17 ` Nicholas Mc Guire
2009-10-21 18:34 ` Steven Rostedt
2009-10-21 18:25 ` David Daney
2009-10-22 11:38 ` Wu Zhangjin
2009-10-22 13:17 ` Steven Rostedt
2009-10-22 13:31 ` Wu Zhangjin
2009-10-22 15:20 ` Steven Rostedt
2009-10-22 15:59 ` David Daney
2009-10-22 16:11 ` Steven Rostedt
2009-10-22 16:16 ` David Daney
2009-10-22 18:00 ` Steven Rostedt
2009-10-22 17:39 ` Wu Zhangjin
2009-10-22 17:58 ` Steven Rostedt
[not found] ` <26008418.post@talk.nabble.com>
2009-10-25 10:48 ` Wu Zhangjin
2009-10-25 10:48 ` Wu Zhangjin
2009-10-25 13:37 ` Patrik Kluba
2009-10-25 13:37 ` Patrik Kluba
2009-10-25 14:22 ` Wu Zhangjin
2009-10-25 15:55 ` Richard Sandiford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1256138506.11274.13.camel@falcon \
--to=wuzhangjin@gmail.com \
--cc=der.herr@hofr.at \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=ralf@linux-mips.org \
--cc=rostedt@goodmis.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).