Commit 6ca63662 authored by Sven Schnelle's avatar Sven Schnelle Committed by Helge Deller
Browse files

parisc: add dynamic ftrace

This patch implements dynamic ftrace for PA-RISC. The required mcount
call sequences can get pretty long, so instead of patching the
whole call sequence out of the functions, we are using
-fpatchable-function-entry from gcc. This puts a configurable amount of
NOPS before/at the start of the function. Taking do_sys_open() as example,
which would look like this when the call is patched out:

1036b248:       08 00 02 40     nop
1036b24c:       08 00 02 40     nop
1036b250:       08 00 02 40     nop
1036b254:       08 00 02 40     nop

1036b258 <do_sys_open>:
1036b258:       08 00 02 40     nop
1036b25c:       08 03 02 41     copy r3,r1
1036b260:       6b c2 3f d9     stw rp,-14(sp)
1036b264:       08 1e 02 43     copy sp,r3
1036b268:       6f c1 01 00     stw,ma r1,80(sp)

When ftrace gets enabled for this function the kernel will patch these
NOPs to:

1036b248:       10 19 57 20     <address of ftrace>
1036b24c:       6f c1 00 80     stw,ma r1,40(sp)
1036b250:       48 21 3f d1     ldw -18(r1),r1
1036b254:       e8 20 c0 02     bv,n r0(r1)

1036b258 <do_sys_open>:
1036b258:       e8 3f 1f df     b,l,n .-c,r1
1036b25c:       08 03 02 41     copy r3,r1
1036b260:       6b c2 3f d9     stw rp,-14(sp)
1036b264:       08 1e 02 43     copy sp,r3
1036b268:       6f c1 01 00     stw,ma r1,80(sp)

So the first NOP in do_sys_open() will be patched to jump backwards into
some minimal trampoline code which pushes a stackframe, saves r1 which
holds the return address, loads the address of the real ftrace function,
and branches to that location. For 64 Bit things are getting a bit more
complicated (and longer) because we must make sure that the address of
ftrace location is 8 byte aligned, and the offset passed to ldd for
fetching the address is 8 byte aligned as well.

Note that gcc has a bug which misplaces the function label, and needs a
patch to make dynamic ftrace work. See
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90751

 for details.

Signed-off-by: default avatarSven Schnelle <svens@stackframe.org>
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
parent 2809b392
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -59,6 +59,8 @@ config PARISC
	select HAVE_ARCH_KGDB
	select HAVE_KPROBES
	select HAVE_KRETPROBES
	select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1)
	select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE

	help
	  The PA-RISC microprocessor is designed by Hewlett-Packard and used
+18 −0
Original line number Diff line number Diff line
@@ -47,6 +47,24 @@ ifneq ($(SUBARCH),$(UTS_MACHINE))
	endif
endif

ifdef CONFIG_DYNAMIC_FTRACE
ifdef CONFIG_64BIT
NOP_COUNT := 8
else
NOP_COUNT := 5
endif

export CC_USING_RECORD_MCOUNT:=1
export CC_USING_PATCHABLE_FUNCTION_ENTRY:=1

KBUILD_AFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY=1
KBUILD_CFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY=1 \
		 -DFTRACE_PATCHABLE_FUNCTION_SIZE=$(NOP_COUNT)

CC_FLAGS_FTRACE := -fpatchable-function-entry=$(NOP_COUNT),$(shell echo $$(($(NOP_COUNT)-1)))
KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/parisc/kernel/module.lds
endif

OBJCOPY_FLAGS =-O binary -R .note -R .comment -S

cflags-y	:= -pipe
+13 −2
Original line number Diff line number Diff line
@@ -5,12 +5,23 @@
#ifndef __ASSEMBLY__
extern void mcount(void);

#define MCOUNT_ADDR		((unsigned long)mcount)
#define MCOUNT_INSN_SIZE	4

#define CC_USING_NOP_MCOUNT
extern unsigned long sys_call_table[];

extern unsigned long return_address(unsigned int);

#ifdef CONFIG_DYNAMIC_FTRACE
extern void ftrace_caller(void);

struct dyn_arch_ftrace {
};

unsigned long ftrace_call_adjust(unsigned long addr);

#endif

#define ftrace_return_address(n) return_address(n)

#endif /* __ASSEMBLY__ */
+5 −4
Original line number Diff line number Diff line
@@ -14,10 +14,11 @@ obj-y := cache.o pacache.o setup.o pdt.o traps.o time.o irq.o \

ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_cache.o = -pg
CFLAGS_REMOVE_perf.o = -pg
CFLAGS_REMOVE_unwind.o = -pg
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_cache.o =  $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_perf.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_unwind.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
endif

obj-$(CONFIG_SMP)	+= smp.o
+64 −0
Original line number Diff line number Diff line
@@ -2012,6 +2012,70 @@ ftrace_stub:
#endif
ENDPROC_CFI(mcount)

#ifdef CONFIG_DYNAMIC_FTRACE

#ifdef CONFIG_64BIT
#define FTRACE_FRAME_SIZE (2*FRAME_SIZE)
#else
#define FTRACE_FRAME_SIZE FRAME_SIZE
#endif
ENTRY_CFI(ftrace_caller, caller,frame=FTRACE_FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
ftrace_caller:
	.global ftrace_caller

	STREG	%r3, -FTRACE_FRAME_SIZE+1*REG_SZ(%sp)
	ldo	-FTRACE_FRAME_SIZE(%sp), %r3
	STREG	%rp, -RP_OFFSET(%r3)

	/* Offset 0 is already allocated for %r1 */
	STREG	%r23, 2*REG_SZ(%r3)
	STREG	%r24, 3*REG_SZ(%r3)
	STREG	%r25, 4*REG_SZ(%r3)
	STREG	%r26, 5*REG_SZ(%r3)
	STREG	%r28, 6*REG_SZ(%r3)
	STREG	%r29, 7*REG_SZ(%r3)
#ifdef CONFIG_64BIT
	STREG	%r19, 8*REG_SZ(%r3)
	STREG	%r20, 9*REG_SZ(%r3)
	STREG	%r21, 10*REG_SZ(%r3)
	STREG	%r22, 11*REG_SZ(%r3)
	STREG	%r27, 12*REG_SZ(%r3)
	STREG	%r31, 13*REG_SZ(%r3)
	loadgp
	ldo	-16(%sp),%r29
#endif
	LDREG	0(%r3), %r25
	copy	%rp, %r26
	ldo	-8(%r25), %r25
	b,l	ftrace_function_trampoline, %rp
	copy	%r3, %r24

	LDREG	-RP_OFFSET(%r3), %rp
	LDREG	2*REG_SZ(%r3), %r23
	LDREG	3*REG_SZ(%r3), %r24
	LDREG	4*REG_SZ(%r3), %r25
	LDREG	5*REG_SZ(%r3), %r26
	LDREG	6*REG_SZ(%r3), %r28
	LDREG	7*REG_SZ(%r3), %r29
#ifdef CONFIG_64BIT
	LDREG	8*REG_SZ(%r3), %r19
	LDREG	9*REG_SZ(%r3), %r20
	LDREG	10*REG_SZ(%r3), %r21
	LDREG	11*REG_SZ(%r3), %r22
	LDREG	12*REG_SZ(%r3), %r27
	LDREG	13*REG_SZ(%r3), %r31
#endif
	LDREG	1*REG_SZ(%r3), %r3

	LDREGM	-FTRACE_FRAME_SIZE(%sp), %r1
	/* Adjust return point to jump back to beginning of traced function */
	ldo	-4(%r1), %r1
	bv,n	(%r1)

ENDPROC_CFI(ftrace_caller)

#endif

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	.align 8
ENTRY_CFI(return_to_handler, caller,frame=FRAME_SIZE)
Loading