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: 66+ 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-22 13:03 ` pajko
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
2009-10-22 20:30 ` Adam Nemet
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
2009-10-22 11:37 ` pajko
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.