Blackfin: initial support for ftrace grapher
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
parent
1c873be744
commit
1ee76d7e16
5 changed files with 115 additions and 0 deletions
|
@ -19,6 +19,7 @@ config RWSEM_XCHGADD_ALGORITHM
|
||||||
|
|
||||||
config BLACKFIN
|
config BLACKFIN
|
||||||
def_bool y
|
def_bool y
|
||||||
|
select HAVE_FUNCTION_GRAPH_TRACER
|
||||||
select HAVE_FUNCTION_TRACER
|
select HAVE_FUNCTION_TRACER
|
||||||
select HAVE_IDE
|
select HAVE_IDE
|
||||||
select HAVE_KERNEL_GZIP
|
select HAVE_KERNEL_GZIP
|
||||||
|
|
|
@ -16,6 +16,9 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o
|
obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o
|
||||||
|
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||||
|
CFLAGS_REMOVE_ftrace.o = -pg
|
||||||
|
|
||||||
obj-$(CONFIG_IPIPE) += ipipe.o
|
obj-$(CONFIG_IPIPE) += ipipe.o
|
||||||
obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o
|
obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o
|
||||||
obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o
|
obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o
|
||||||
|
|
|
@ -35,6 +35,28 @@ ENTRY(__mcount)
|
||||||
cc = r2 == r3;
|
cc = r2 == r3;
|
||||||
if ! cc jump .Ldo_trace;
|
if ! cc jump .Ldo_trace;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
/* if the ftrace_graph_return function pointer is not set to
|
||||||
|
* the ftrace_stub entry, call prepare_ftrace_return().
|
||||||
|
*/
|
||||||
|
p0.l = _ftrace_graph_return;
|
||||||
|
p0.h = _ftrace_graph_return;
|
||||||
|
r3 = [p0];
|
||||||
|
cc = r2 == r3;
|
||||||
|
if ! cc jump _ftrace_graph_caller;
|
||||||
|
|
||||||
|
/* similarly, if the ftrace_graph_entry function pointer is not
|
||||||
|
* set to the ftrace_graph_entry_stub entry, ...
|
||||||
|
*/
|
||||||
|
p0.l = _ftrace_graph_entry;
|
||||||
|
p0.h = _ftrace_graph_entry;
|
||||||
|
r2.l = _ftrace_graph_entry_stub;
|
||||||
|
r2.h = _ftrace_graph_entry_stub;
|
||||||
|
r3 = [p0];
|
||||||
|
cc = r2 == r3;
|
||||||
|
if ! cc jump _ftrace_graph_caller;
|
||||||
|
#endif
|
||||||
|
|
||||||
r2 = [sp++];
|
r2 = [sp++];
|
||||||
rts;
|
rts;
|
||||||
|
|
||||||
|
@ -61,6 +83,7 @@ ENTRY(__mcount)
|
||||||
call (p0);
|
call (p0);
|
||||||
|
|
||||||
/* restore state and get out of dodge */
|
/* restore state and get out of dodge */
|
||||||
|
.Lfinish_trace:
|
||||||
rets = [sp++];
|
rets = [sp++];
|
||||||
r1 = [sp++];
|
r1 = [sp++];
|
||||||
r0 = [sp++];
|
r0 = [sp++];
|
||||||
|
@ -70,3 +93,48 @@ ENTRY(__mcount)
|
||||||
_ftrace_stub:
|
_ftrace_stub:
|
||||||
rts;
|
rts;
|
||||||
ENDPROC(__mcount)
|
ENDPROC(__mcount)
|
||||||
|
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
/* The prepare_ftrace_return() function is similar to the trace function
|
||||||
|
* except it takes a pointer to the location of the frompc. This is so
|
||||||
|
* the prepare_ftrace_return() can hijack it temporarily for probing
|
||||||
|
* purposes.
|
||||||
|
*/
|
||||||
|
ENTRY(_ftrace_graph_caller)
|
||||||
|
/* save first/second function arg and the return register */
|
||||||
|
[--sp] = r0;
|
||||||
|
[--sp] = r1;
|
||||||
|
[--sp] = rets;
|
||||||
|
|
||||||
|
r0 = fp;
|
||||||
|
r1 = rets;
|
||||||
|
r0 += 4;
|
||||||
|
r1 += -MCOUNT_INSN_SIZE;
|
||||||
|
call _prepare_ftrace_return;
|
||||||
|
|
||||||
|
jump .Lfinish_trace;
|
||||||
|
ENDPROC(_ftrace_graph_caller)
|
||||||
|
|
||||||
|
/* Undo the rewrite caused by ftrace_graph_caller(). The common function
|
||||||
|
* ftrace_return_to_handler() will return the original rets so we can
|
||||||
|
* restore it and be on our way.
|
||||||
|
*/
|
||||||
|
ENTRY(_return_to_handler)
|
||||||
|
/* make sure original return values are saved */
|
||||||
|
[--sp] = p0;
|
||||||
|
[--sp] = r0;
|
||||||
|
[--sp] = r1;
|
||||||
|
|
||||||
|
/* get original return address */
|
||||||
|
call _ftrace_return_to_handler;
|
||||||
|
rets = r0;
|
||||||
|
|
||||||
|
/* anomaly 05000371 - make sure we have at least three instructions
|
||||||
|
* between rets setting and the return
|
||||||
|
*/
|
||||||
|
r1 = [sp++];
|
||||||
|
r0 = [sp++];
|
||||||
|
p0 = [sp++];
|
||||||
|
rts;
|
||||||
|
ENDPROC(_return_to_handler)
|
||||||
|
#endif
|
||||||
|
|
42
arch/blackfin/kernel/ftrace.c
Normal file
42
arch/blackfin/kernel/ftrace.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* ftrace graph code
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Analog Devices Inc.
|
||||||
|
* Licensed under the GPL-2 or later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/ftrace.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
struct ftrace_graph_ent trace;
|
||||||
|
unsigned long return_hooker = (unsigned long)&return_to_handler;
|
||||||
|
|
||||||
|
if (unlikely(atomic_read(¤t->tracing_graph_pause)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ftrace_push_return_trace(*parent, self_addr, &trace.depth) == -EBUSY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
trace.func = self_addr;
|
||||||
|
|
||||||
|
/* Only trace if the calling function expects to */
|
||||||
|
if (!ftrace_graph_entry(&trace)) {
|
||||||
|
current->curr_ret_stack--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all is well in the world ! hijack RETS ... */
|
||||||
|
*parent = return_hooker;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -54,6 +54,7 @@ SECTIONS
|
||||||
SCHED_TEXT
|
SCHED_TEXT
|
||||||
#endif
|
#endif
|
||||||
LOCK_TEXT
|
LOCK_TEXT
|
||||||
|
IRQENTRY_TEXT
|
||||||
KPROBES_TEXT
|
KPROBES_TEXT
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
*(.fixup)
|
*(.fixup)
|
||||||
|
|
Loading…
Add table
Reference in a new issue