Skip to content

Commit

Permalink
Merge branch 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/deller/parisc-linux

Pull parisc ftrace fixes from Helge Deller:
 "This is (most likely) the last pull request for v4.6 for the parisc
  architecture.

  It fixes the FTRACE feature for parisc, which is horribly broken since
   quite some time and doesn't even compile.  This patch just fixes the
  bare minimum (it actually removes more lines than it adds), so that
  the function tracer works again on 32- and 64bit kernels.

  I've queued up additional patches on top of this patch which e.g. add
  the syscall tracer, but those have to wait for the merge window for
  v4.7."

* 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Fix ftrace function tracer
  • Loading branch information
Linus Torvalds committed Apr 15, 2016
2 parents 806fdcc + 366dd4e commit 60ea7bb
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 168 deletions.
4 changes: 2 additions & 2 deletions arch/parisc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ config PARISC
select ARCH_MIGHT_HAVE_PC_PARPORT
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_FUNCTION_TRACER if 64BIT
select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select ARCH_WANT_FRAME_POINTERS
select RTC_CLASS
select RTC_DRV_GENERIC
Expand Down
4 changes: 4 additions & 0 deletions arch/parisc/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ menu "Kernel hacking"

source "lib/Kconfig.debug"

config TRACE_IRQFLAGS_SUPPORT
def_bool y

config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
depends on DEBUG_KERNEL
default y
help
Mark the kernel read-only data as write-protected in the pagetables,
in order to catch accidental (and incorrect) writes to such const
Expand Down
4 changes: 1 addition & 3 deletions arch/parisc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ cflags-y += -mdisable-fpregs

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

# Use long jumps instead of long branches (needed if your linker fails to
# link a too big vmlinux executable). Not enabled for building modules.
Expand Down
18 changes: 1 addition & 17 deletions arch/parisc/include/asm/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,7 @@
#ifndef __ASSEMBLY__
extern void mcount(void);

/*
* Stack of return addresses for functions of a thread.
* Used in struct thread_info
*/
struct ftrace_ret_stack {
unsigned long ret;
unsigned long func;
unsigned long long calltime;
};

/*
* Primary handler of a function return.
* It relays on ftrace_return_to_handler.
* Defined in entry.S
*/
extern void return_to_handler(void);

#define MCOUNT_INSN_SIZE 4

extern unsigned long return_address(unsigned int);

Expand Down
4 changes: 0 additions & 4 deletions arch/parisc/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_cache.o = -pg
CFLAGS_REMOVE_irq.o = -pg
CFLAGS_REMOVE_pacache.o = -pg
CFLAGS_REMOVE_perf.o = -pg
CFLAGS_REMOVE_traps.o = -pg
CFLAGS_REMOVE_unaligned.o = -pg
CFLAGS_REMOVE_unwind.o = -pg
endif

Expand Down
93 changes: 74 additions & 19 deletions arch/parisc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -1970,43 +1970,98 @@ pt_regs_ok:
b intr_restore
copy %r25,%r16

.import schedule,code
syscall_do_resched:
BL schedule,%r2
load32 syscall_check_resched,%r2 /* if resched, we start over again */
load32 schedule,%r19
bv %r0(%r19) /* jumps to schedule() */
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#else
nop
#endif
b syscall_check_resched /* if resched, we start over again */
nop
ENDPROC(syscall_exit)


#ifdef CONFIG_FUNCTION_TRACER

.import ftrace_function_trampoline,code
ENTRY(_mcount)
copy %r3, %arg2
.align L1_CACHE_BYTES
.globl mcount
.type mcount, @function
ENTRY(mcount)
_mcount:
.export _mcount,data
.proc
.callinfo caller,frame=0
.entry
/*
* The 64bit mcount() function pointer needs 4 dwords, of which the
* first two are free. We optimize it here and put 2 instructions for
* calling mcount(), and 2 instructions for ftrace_stub(). That way we
* have all on one L1 cacheline.
*/
b ftrace_function_trampoline
copy %r3, %arg2 /* caller original %sp */
ftrace_stub:
.globl ftrace_stub
.type ftrace_stub, @function
#ifdef CONFIG_64BIT
bve (%rp)
#else
bv %r0(%rp)
#endif
nop
ENDPROC(_mcount)
#ifdef CONFIG_64BIT
.dword mcount
.dword 0 /* code in head.S puts value of global gp here */
#endif
.exit
.procend
ENDPROC(mcount)

.align 8
.globl return_to_handler
.type return_to_handler, @function
ENTRY(return_to_handler)
load32 return_trampoline, %rp
copy %ret0, %arg0
copy %ret1, %arg1
b ftrace_return_to_handler
nop
return_trampoline:
copy %ret0, %rp
copy %r23, %ret0
copy %r24, %ret1
.proc
.callinfo caller,frame=FRAME_SIZE
.entry
.export parisc_return_to_handler,data
parisc_return_to_handler:
copy %r3,%r1
STREG %r0,-RP_OFFSET(%sp) /* store 0 as %rp */
copy %sp,%r3
STREGM %r1,FRAME_SIZE(%sp)
STREG %ret0,8(%r3)
STREG %ret1,16(%r3)

.globl ftrace_stub
ftrace_stub:
#ifdef CONFIG_64BIT
loadgp
#endif

/* call ftrace_return_to_handler(0) */
#ifdef CONFIG_64BIT
ldo -16(%sp),%ret1 /* Reference param save area */
#endif
BL ftrace_return_to_handler,%r2
ldi 0,%r26
copy %ret0,%rp

/* restore original return values */
LDREG 8(%r3),%ret0
LDREG 16(%r3),%ret1

/* return from function */
#ifdef CONFIG_64BIT
bve (%rp)
#else
bv %r0(%rp)
nop
#endif
LDREGM -FRAME_SIZE(%sp),%r3
.exit
.procend
ENDPROC(return_to_handler)

#endif /* CONFIG_FUNCTION_TRACER */

#ifdef CONFIG_IRQSTACKS
Expand Down
146 changes: 23 additions & 123 deletions arch/parisc/kernel/ftrace.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Code for tracing calls in Linux kernel.
* Copyright (C) 2009 Helge Deller <deller@gmx.de>
* Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
*
* based on code for x86 which is:
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
Expand All @@ -13,104 +13,21 @@
#include <linux/init.h>
#include <linux/ftrace.h>

#include <asm/assembly.h>
#include <asm/sections.h>
#include <asm/ftrace.h>



#ifdef CONFIG_FUNCTION_GRAPH_TRACER

/* Add a function return address to the trace stack on thread info.*/
static int push_return_trace(unsigned long ret, unsigned long long time,
unsigned long func, int *depth)
{
int index;

if (!current->ret_stack)
return -EBUSY;

/* The return trace stack is full */
if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
atomic_inc(&current->trace_overrun);
return -EBUSY;
}

index = ++current->curr_ret_stack;
barrier();
current->ret_stack[index].ret = ret;
current->ret_stack[index].func = func;
current->ret_stack[index].calltime = time;
*depth = index;

return 0;
}

/* Retrieve a function return address to the trace stack on thread info.*/
static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
{
int index;

index = current->curr_ret_stack;

if (unlikely(index < 0)) {
ftrace_graph_stop();
WARN_ON(1);
/* Might as well panic, otherwise we have no where to go */
*ret = (unsigned long)
dereference_function_descriptor(&panic);
return;
}

*ret = current->ret_stack[index].ret;
trace->func = current->ret_stack[index].func;
trace->calltime = current->ret_stack[index].calltime;
trace->overrun = atomic_read(&current->trace_overrun);
trace->depth = index;
barrier();
current->curr_ret_stack--;

}

/*
* Send the trace to the ring-buffer.
* @return the original return address.
*/
unsigned long ftrace_return_to_handler(unsigned long retval0,
unsigned long retval1)
{
struct ftrace_graph_ret trace;
unsigned long ret;

pop_return_trace(&trace, &ret);
trace.rettime = local_clock();
ftrace_graph_return(&trace);

if (unlikely(!ret)) {
ftrace_graph_stop();
WARN_ON(1);
/* Might as well panic. What else to do? */
ret = (unsigned long)
dereference_function_descriptor(&panic);
}

/* HACK: we hand over the old functions' return values
in %r23 and %r24. Assembly in entry.S will take care
and move those to their final registers %ret0 and %ret1 */
asm( "copy %0, %%r23 \n\t"
"copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );

return ret;
}

/*
* 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)
static void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
{
unsigned long old;
unsigned long long calltime;
struct ftrace_graph_ent trace;
extern int parisc_return_to_handler;

if (unlikely(ftrace_graph_is_dead()))
return;
Expand All @@ -119,64 +36,47 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return;

old = *parent;
*parent = (unsigned long)
dereference_function_descriptor(&return_to_handler);

if (unlikely(!__kernel_text_address(old))) {
ftrace_graph_stop();
*parent = old;
WARN_ON(1);
return;
}

calltime = local_clock();
trace.func = self_addr;
trace.depth = current->curr_ret_stack + 1;

if (push_return_trace(old, calltime,
self_addr, &trace.depth) == -EBUSY) {
*parent = old;
/* Only trace if the calling function expects to */
if (!ftrace_graph_entry(&trace))
return;
}

trace.func = self_addr;
if (ftrace_push_return_trace(old, self_addr, &trace.depth,
0 ) == -EBUSY)
return;

/* Only trace if the calling function expects to */
if (!ftrace_graph_entry(&trace)) {
current->curr_ret_stack--;
*parent = old;
}
/* activate parisc_return_to_handler() as return point */
*parent = (unsigned long) &parisc_return_to_handler;
}

#endif /* CONFIG_FUNCTION_GRAPH_TRACER */


void ftrace_function_trampoline(unsigned long parent,
void notrace ftrace_function_trampoline(unsigned long parent,
unsigned long self_addr,
unsigned long org_sp_gr3)
{
extern ftrace_func_t ftrace_trace_function;
extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);

if (ftrace_trace_function != ftrace_stub) {
ftrace_trace_function(parent, self_addr);
/* struct ftrace_ops *op, struct pt_regs *regs); */
ftrace_trace_function(parent, self_addr, NULL, NULL);
return;
}

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
if (ftrace_graph_entry && ftrace_graph_return) {
unsigned long sp;
if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
ftrace_graph_entry != ftrace_graph_entry_stub) {
unsigned long *parent_rp;

asm volatile ("copy %%r30, %0" : "=r"(sp));
/* sanity check: is stack pointer which we got from
assembler function in entry.S in a reasonable
range compared to current stack pointer? */
if ((sp - org_sp_gr3) > 0x400)
return;

/* calculate pointer to %rp in stack */
parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
/* sanity check: parent_rp should hold parent */
if (*parent_rp != parent)
return;

prepare_ftrace_return(parent_rp, self_addr);
return;
}
Expand Down
Loading

0 comments on commit 60ea7bb

Please sign in to comment.