Skip to content

Commit 366dd4e

Browse files
committedApr 14, 2016
parisc: Fix ftrace function tracer
Fix the FTRACE function tracer for 32- and 64-bit kernel. The former code was horribly broken. Reimplement most coding in assembly and utilize optimizations, e.g. put mcount() and ftrace_stub() into one L1 cacheline. Signed-off-by: Helge Deller <deller@gmx.de>
1 parent b562e44 commit 366dd4e

File tree

8 files changed

+114
-168
lines changed

8 files changed

+114
-168
lines changed
 

‎arch/parisc/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ config PARISC
44
select ARCH_MIGHT_HAVE_PC_PARPORT
55
select HAVE_IDE
66
select HAVE_OPROFILE
7-
select HAVE_FUNCTION_TRACER if 64BIT
8-
select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
7+
select HAVE_FUNCTION_TRACER
8+
select HAVE_FUNCTION_GRAPH_TRACER
99
select ARCH_WANT_FRAME_POINTERS
1010
select RTC_CLASS
1111
select RTC_DRV_GENERIC

‎arch/parisc/Kconfig.debug

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ menu "Kernel hacking"
22

33
source "lib/Kconfig.debug"
44

5+
config TRACE_IRQFLAGS_SUPPORT
6+
def_bool y
7+
58
config DEBUG_RODATA
69
bool "Write protect kernel read-only data structures"
710
depends on DEBUG_KERNEL
11+
default y
812
help
913
Mark the kernel read-only data as write-protected in the pagetables,
1014
in order to catch accidental (and incorrect) writes to such const

‎arch/parisc/Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ cflags-y += -mdisable-fpregs
6262

6363
# Without this, "ld -r" results in .text sections that are too big
6464
# (> 0x40000) for branches to reach stubs.
65-
ifndef CONFIG_FUNCTION_TRACER
66-
cflags-y += -ffunction-sections
67-
endif
65+
cflags-y += -ffunction-sections
6866

6967
# Use long jumps instead of long branches (needed if your linker fails to
7068
# link a too big vmlinux executable). Not enabled for building modules.

‎arch/parisc/include/asm/ftrace.h

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,7 @@
44
#ifndef __ASSEMBLY__
55
extern void mcount(void);
66

7-
/*
8-
* Stack of return addresses for functions of a thread.
9-
* Used in struct thread_info
10-
*/
11-
struct ftrace_ret_stack {
12-
unsigned long ret;
13-
unsigned long func;
14-
unsigned long long calltime;
15-
};
16-
17-
/*
18-
* Primary handler of a function return.
19-
* It relays on ftrace_return_to_handler.
20-
* Defined in entry.S
21-
*/
22-
extern void return_to_handler(void);
23-
7+
#define MCOUNT_INSN_SIZE 4
248

259
extern unsigned long return_address(unsigned int);
2610

‎arch/parisc/kernel/Makefile

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ ifdef CONFIG_FUNCTION_TRACER
1515
# Do not profile debug and lowlevel utilities
1616
CFLAGS_REMOVE_ftrace.o = -pg
1717
CFLAGS_REMOVE_cache.o = -pg
18-
CFLAGS_REMOVE_irq.o = -pg
19-
CFLAGS_REMOVE_pacache.o = -pg
2018
CFLAGS_REMOVE_perf.o = -pg
21-
CFLAGS_REMOVE_traps.o = -pg
22-
CFLAGS_REMOVE_unaligned.o = -pg
2319
CFLAGS_REMOVE_unwind.o = -pg
2420
endif
2521

‎arch/parisc/kernel/entry.S

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,43 +1970,98 @@ pt_regs_ok:
19701970
b intr_restore
19711971
copy %r25,%r16
19721972

1973-
.import schedule,code
19741973
syscall_do_resched:
1975-
BL schedule,%r2
1974+
load32 syscall_check_resched,%r2 /* if resched, we start over again */
1975+
load32 schedule,%r19
1976+
bv %r0(%r19) /* jumps to schedule() */
19761977
#ifdef CONFIG_64BIT
19771978
ldo -16(%r30),%r29 /* Reference param save area */
19781979
#else
19791980
nop
19801981
#endif
1981-
b syscall_check_resched /* if resched, we start over again */
1982-
nop
19831982
ENDPROC(syscall_exit)
19841983

19851984

19861985
#ifdef CONFIG_FUNCTION_TRACER
1986+
19871987
.import ftrace_function_trampoline,code
1988-
ENTRY(_mcount)
1989-
copy %r3, %arg2
1988+
.align L1_CACHE_BYTES
1989+
.globl mcount
1990+
.type mcount, @function
1991+
ENTRY(mcount)
1992+
_mcount:
1993+
.export _mcount,data
1994+
.proc
1995+
.callinfo caller,frame=0
1996+
.entry
1997+
/*
1998+
* The 64bit mcount() function pointer needs 4 dwords, of which the
1999+
* first two are free. We optimize it here and put 2 instructions for
2000+
* calling mcount(), and 2 instructions for ftrace_stub(). That way we
2001+
* have all on one L1 cacheline.
2002+
*/
19902003
b ftrace_function_trampoline
2004+
copy %r3, %arg2 /* caller original %sp */
2005+
ftrace_stub:
2006+
.globl ftrace_stub
2007+
.type ftrace_stub, @function
2008+
#ifdef CONFIG_64BIT
2009+
bve (%rp)
2010+
#else
2011+
bv %r0(%rp)
2012+
#endif
19912013
nop
1992-
ENDPROC(_mcount)
2014+
#ifdef CONFIG_64BIT
2015+
.dword mcount
2016+
.dword 0 /* code in head.S puts value of global gp here */
2017+
#endif
2018+
.exit
2019+
.procend
2020+
ENDPROC(mcount)
19932021

2022+
.align 8
2023+
.globl return_to_handler
2024+
.type return_to_handler, @function
19942025
ENTRY(return_to_handler)
1995-
load32 return_trampoline, %rp
1996-
copy %ret0, %arg0
1997-
copy %ret1, %arg1
1998-
b ftrace_return_to_handler
1999-
nop
2000-
return_trampoline:
2001-
copy %ret0, %rp
2002-
copy %r23, %ret0
2003-
copy %r24, %ret1
2026+
.proc
2027+
.callinfo caller,frame=FRAME_SIZE
2028+
.entry
2029+
.export parisc_return_to_handler,data
2030+
parisc_return_to_handler:
2031+
copy %r3,%r1
2032+
STREG %r0,-RP_OFFSET(%sp) /* store 0 as %rp */
2033+
copy %sp,%r3
2034+
STREGM %r1,FRAME_SIZE(%sp)
2035+
STREG %ret0,8(%r3)
2036+
STREG %ret1,16(%r3)
20042037

2005-
.globl ftrace_stub
2006-
ftrace_stub:
2038+
#ifdef CONFIG_64BIT
2039+
loadgp
2040+
#endif
2041+
2042+
/* call ftrace_return_to_handler(0) */
2043+
#ifdef CONFIG_64BIT
2044+
ldo -16(%sp),%ret1 /* Reference param save area */
2045+
#endif
2046+
BL ftrace_return_to_handler,%r2
2047+
ldi 0,%r26
2048+
copy %ret0,%rp
2049+
2050+
/* restore original return values */
2051+
LDREG 8(%r3),%ret0
2052+
LDREG 16(%r3),%ret1
2053+
2054+
/* return from function */
2055+
#ifdef CONFIG_64BIT
2056+
bve (%rp)
2057+
#else
20072058
bv %r0(%rp)
2008-
nop
2059+
#endif
2060+
LDREGM -FRAME_SIZE(%sp),%r3
2061+
.exit
2062+
.procend
20092063
ENDPROC(return_to_handler)
2064+
20102065
#endif /* CONFIG_FUNCTION_TRACER */
20112066

20122067
#ifdef CONFIG_IRQSTACKS

‎arch/parisc/kernel/ftrace.c

Lines changed: 23 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Code for tracing calls in Linux kernel.
3-
* Copyright (C) 2009 Helge Deller <deller@gmx.de>
3+
* Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
44
*
55
* based on code for x86 which is:
66
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
@@ -13,104 +13,21 @@
1313
#include <linux/init.h>
1414
#include <linux/ftrace.h>
1515

16+
#include <asm/assembly.h>
1617
#include <asm/sections.h>
1718
#include <asm/ftrace.h>
1819

1920

20-
2121
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
22-
23-
/* Add a function return address to the trace stack on thread info.*/
24-
static int push_return_trace(unsigned long ret, unsigned long long time,
25-
unsigned long func, int *depth)
26-
{
27-
int index;
28-
29-
if (!current->ret_stack)
30-
return -EBUSY;
31-
32-
/* The return trace stack is full */
33-
if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
34-
atomic_inc(&current->trace_overrun);
35-
return -EBUSY;
36-
}
37-
38-
index = ++current->curr_ret_stack;
39-
barrier();
40-
current->ret_stack[index].ret = ret;
41-
current->ret_stack[index].func = func;
42-
current->ret_stack[index].calltime = time;
43-
*depth = index;
44-
45-
return 0;
46-
}
47-
48-
/* Retrieve a function return address to the trace stack on thread info.*/
49-
static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
50-
{
51-
int index;
52-
53-
index = current->curr_ret_stack;
54-
55-
if (unlikely(index < 0)) {
56-
ftrace_graph_stop();
57-
WARN_ON(1);
58-
/* Might as well panic, otherwise we have no where to go */
59-
*ret = (unsigned long)
60-
dereference_function_descriptor(&panic);
61-
return;
62-
}
63-
64-
*ret = current->ret_stack[index].ret;
65-
trace->func = current->ret_stack[index].func;
66-
trace->calltime = current->ret_stack[index].calltime;
67-
trace->overrun = atomic_read(&current->trace_overrun);
68-
trace->depth = index;
69-
barrier();
70-
current->curr_ret_stack--;
71-
72-
}
73-
74-
/*
75-
* Send the trace to the ring-buffer.
76-
* @return the original return address.
77-
*/
78-
unsigned long ftrace_return_to_handler(unsigned long retval0,
79-
unsigned long retval1)
80-
{
81-
struct ftrace_graph_ret trace;
82-
unsigned long ret;
83-
84-
pop_return_trace(&trace, &ret);
85-
trace.rettime = local_clock();
86-
ftrace_graph_return(&trace);
87-
88-
if (unlikely(!ret)) {
89-
ftrace_graph_stop();
90-
WARN_ON(1);
91-
/* Might as well panic. What else to do? */
92-
ret = (unsigned long)
93-
dereference_function_descriptor(&panic);
94-
}
95-
96-
/* HACK: we hand over the old functions' return values
97-
in %r23 and %r24. Assembly in entry.S will take care
98-
and move those to their final registers %ret0 and %ret1 */
99-
asm( "copy %0, %%r23 \n\t"
100-
"copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );
101-
102-
return ret;
103-
}
104-
10522
/*
10623
* Hook the return address and push it in the stack of return addrs
10724
* in current thread info.
10825
*/
109-
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
26+
static void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
11027
{
11128
unsigned long old;
112-
unsigned long long calltime;
11329
struct ftrace_graph_ent trace;
30+
extern int parisc_return_to_handler;
11431

11532
if (unlikely(ftrace_graph_is_dead()))
11633
return;
@@ -119,64 +36,47 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
11936
return;
12037

12138
old = *parent;
122-
*parent = (unsigned long)
123-
dereference_function_descriptor(&return_to_handler);
12439

125-
if (unlikely(!__kernel_text_address(old))) {
126-
ftrace_graph_stop();
127-
*parent = old;
128-
WARN_ON(1);
129-
return;
130-
}
131-
132-
calltime = local_clock();
40+
trace.func = self_addr;
41+
trace.depth = current->curr_ret_stack + 1;
13342

134-
if (push_return_trace(old, calltime,
135-
self_addr, &trace.depth) == -EBUSY) {
136-
*parent = old;
43+
/* Only trace if the calling function expects to */
44+
if (!ftrace_graph_entry(&trace))
13745
return;
138-
}
13946

140-
trace.func = self_addr;
47+
if (ftrace_push_return_trace(old, self_addr, &trace.depth,
48+
0 ) == -EBUSY)
49+
return;
14150

142-
/* Only trace if the calling function expects to */
143-
if (!ftrace_graph_entry(&trace)) {
144-
current->curr_ret_stack--;
145-
*parent = old;
146-
}
51+
/* activate parisc_return_to_handler() as return point */
52+
*parent = (unsigned long) &parisc_return_to_handler;
14753
}
148-
14954
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
15055

151-
152-
void ftrace_function_trampoline(unsigned long parent,
56+
void notrace ftrace_function_trampoline(unsigned long parent,
15357
unsigned long self_addr,
15458
unsigned long org_sp_gr3)
15559
{
156-
extern ftrace_func_t ftrace_trace_function;
60+
extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */
61+
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
15762

15863
if (ftrace_trace_function != ftrace_stub) {
159-
ftrace_trace_function(parent, self_addr);
64+
/* struct ftrace_ops *op, struct pt_regs *regs); */
65+
ftrace_trace_function(parent, self_addr, NULL, NULL);
16066
return;
16167
}
68+
16269
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
163-
if (ftrace_graph_entry && ftrace_graph_return) {
164-
unsigned long sp;
70+
if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
71+
ftrace_graph_entry != ftrace_graph_entry_stub) {
16572
unsigned long *parent_rp;
16673

167-
asm volatile ("copy %%r30, %0" : "=r"(sp));
168-
/* sanity check: is stack pointer which we got from
169-
assembler function in entry.S in a reasonable
170-
range compared to current stack pointer? */
171-
if ((sp - org_sp_gr3) > 0x400)
172-
return;
173-
17474
/* calculate pointer to %rp in stack */
175-
parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
75+
parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
17676
/* sanity check: parent_rp should hold parent */
17777
if (*parent_rp != parent)
17878
return;
179-
79+
18080
prepare_ftrace_return(parent_rp, self_addr);
18181
return;
18282
}

0 commit comments

Comments
 (0)