diff options
| -rw-r--r-- | arch/arm/kernel/Makefile | 3 | ||||
| -rw-r--r-- | arch/arm/kernel/entry-common.S | 46 | ||||
| -rw-r--r-- | arch/arm/kernel/ftrace.c | 34 | 
3 files changed, 82 insertions, 1 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5b9b268f4fb..679851a9f58 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -5,7 +5,7 @@  CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)  AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET) -ifdef CONFIG_DYNAMIC_FTRACE +ifdef CONFIG_FUNCTION_TRACER  CFLAGS_REMOVE_ftrace.o = -pg  endif @@ -33,6 +33,7 @@ obj-$(CONFIG_SMP)		+= smp.o  obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o  obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o  obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o  obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o  obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-decode.o  obj-$(CONFIG_ATAGS_PROC)	+= atags.o diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index fe1d5862b19..9f176621166 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -148,6 +148,20 @@ ENDPROC(ret_from_fork)  	adr	r0, .Lftrace_stub  	cmp	r0, r2  	bne	1f + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +	ldr     r1, =ftrace_graph_return +	ldr     r2, [r1] +	cmp     r0, r2 +	bne     ftrace_graph_caller\suffix + +	ldr     r1, =ftrace_graph_entry +	ldr     r2, [r1] +	ldr     r0, =ftrace_graph_entry_stub +	cmp     r0, r2 +	bne     ftrace_graph_caller\suffix +#endif +  	mcount_exit  1: 	mcount_get_lr	r1			@ lr of instrumented func @@ -172,6 +186,15 @@ ftrace_call\suffix:  	mcount_exit  .endm +.macro __ftrace_graph_caller +	sub	r0, fp, #4		@ &lr of instrumented routine (&parent) +	mov	r1, lr			@ instrumented routine (func) +	sub	r1, r1, #MCOUNT_INSN_SIZE +	mov	r2, fp			@ frame pointer +	bl	prepare_ftrace_return +	mcount_exit +.endm +  #ifdef CONFIG_OLD_MCOUNT  /*   * mcount @@ -206,6 +229,12 @@ ENTRY(ftrace_caller_old)  ENDPROC(ftrace_caller_old)  #endif +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +ENTRY(ftrace_graph_caller_old) +	__ftrace_graph_caller +ENDPROC(ftrace_graph_caller_old) +#endif +  .purgem mcount_enter  .purgem mcount_get_lr  .purgem mcount_exit @@ -244,10 +273,27 @@ ENTRY(ftrace_caller)  ENDPROC(ftrace_caller)  #endif +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +ENTRY(ftrace_graph_caller) +	__ftrace_graph_caller +ENDPROC(ftrace_graph_caller) +#endif +  .purgem mcount_enter  .purgem mcount_get_lr  .purgem mcount_exit +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +	.globl return_to_handler +return_to_handler: +	stmdb	sp!, {r0-r3} +	mov	r0, fp			@ frame pointer +	bl	ftrace_return_to_handler +	mov	lr, r0			@ r0 has real ret addr +	ldmia	sp!, {r0-r3} +	mov	pc, lr +#endif +  ENTRY(ftrace_stub)  .Lftrace_stub:  	mov	pc, lr diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 971ac8c36ea..7a702a50287 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -24,6 +24,7 @@  #define	NOP		0xe8bd4000	/* pop {lr} */  #endif +#ifdef CONFIG_DYNAMIC_FTRACE  #ifdef CONFIG_OLD_MCOUNT  #define OLD_MCOUNT_ADDR	((unsigned long) mcount)  #define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) @@ -193,3 +194,36 @@ int __init ftrace_dyn_arch_init(void *data)  	return 0;  } +#endif /* CONFIG_DYNAMIC_FTRACE */ + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, +			   unsigned long frame_pointer) +{ +	unsigned long return_hooker = (unsigned long) &return_to_handler; +	struct ftrace_graph_ent trace; +	unsigned long old; +	int err; + +	if (unlikely(atomic_read(¤t->tracing_graph_pause))) +		return; + +	old = *parent; +	*parent = return_hooker; + +	err = ftrace_push_return_trace(old, self_addr, &trace.depth, +				       frame_pointer); +	if (err == -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 */  |